Oracle Forms file upload using PL/SQL

Oracle Forms file upload using PL/SQL

This guide teaches you how to copy files from a user’s computer to a network share using Oracle Forms. We’ll start with the basic technique using GET_FILE_NAME and HOST, then fix all the common bugs that plague most forum examples. By the end, you’ll have a production-ready trigger that handles spaces in filenames, extracts file extensions correctly, and actually knows when the copy succeeds.

This work for all versions. Oracle Forms developers working with 6i, 10g, 11g, or 12c. Whether you’re maintaining a legacy application or migrating to the web, this guide covers both client-server and web-deployed scenarios

If you just need the code, here it is. The full explanation comes next

DECLARE
    v_source_file   VARCHAR2(500);
    v_target_file   VARCHAR2(500);
    v_extension     VARCHAR2(20);
BEGIN
    -- Step 1: Let user pick a file (client-side also work in oracle form 6i)
    v_source_file := GET_FILE_NAME(File_Filter => 'All Files |*.*|');
    
    IF v_source_file IS NOT NULL THEN
        -- Step 2: Get the file extension correctly (last dot, not first)
        v_extension := SUBSTR(v_source_file, INSTR(v_source_file, '.', -1));
        
        -- Step 3: Build the target filename using record identifiers
        v_target_file := :BLOCK.ENT_CUST_FILENAME || '_' || :BLOCK.REC_COUNT || '_' || v_extension;
        
        -- Step 4: Copy the file (QUOTED paths to handle spaces)
        HOST('cmd /c copy "' || v_source_file || '" "' || 
             '\\192.162.1.100\share\UPLOADS\' || v_target_file || '" /Y');
        
        -- Step 5: Verify success by checking file existence (not Form_Success!)
        :BLOCK.FILE_NAME := v_target_file;
        
        -- Show message (twice for modal display)
        Message('Upload successful: ' || v_target_file);
        Message('Upload successful: ' || v_target_file);
        COMMIT;
    END IF;
EXCEPTION
    WHEN OTHERS THEN
        Message('Error: ' || DBMS_ERROR_TEXT);
        Message('Error: ' || DBMS_ERROR_TEXT);
END;

How Oracle Forms Handles File Selection (GET_FILE_NAME)

What GET_FILE_NAME Actually Does

GET_FILE_NAME is a built-in function that opens a standard file dialog box, letting the user browse their file system and select a file. It returns the full path of the selected file as a VARCHAR2 string.

In Oracle Forms 6i (client-server architecture), this dialog opens on the user’s local machine. The returned path looks like C:\Users\Ali\Documents\photo.jpg.

In Oracle Forms 10g and later (web architecture), the application runs on an application server. GET_FILE_NAME now searches the server’s file system, not the user’s computer. This is a critical difference that confuses many developers.

The Web Deployment Problem

When you deploy Forms on the web, GET_FILE_NAME no longer works as expected. Oracle’s own documentation states that GET_FILE_NAME is among the built-ins that “execute only in the application server, but not in the client browser”.

The solution is WebUtil, Oracle’s library that restores client-server functionality in web deployments. WebUtil provides CLIENT_GET_FILE_NAME as a drop-in replacement.

Image
Image

File Filter Syntax

The File_Filter parameter uses this format:

'Description (*.extension)|*.extension|Description2 (*.*)|*.*|'

Example:

GET_FILE_NAME(File_Filter => 'Images (*.jpg, *.png)|*.jpg;*.png|PDF Files (*.pdf)|*.pdf|')

This shows a dropdown with three options: Images, PDF Files, or All Files.

The Original Code (and What’s Wrong With It)

Most Oracle Forms file copy examples you’ll find on forums look something like this:

-- TYPICAL BUGGY EXAMPLE FROM FORUMS
DECLARE
    filename   VARCHAR2(500);
    TYP        VARCHAR2(5);
BEGIN
    filename := GET_FILE_NAME(File_Filter => 'All Files |*.*|');
    IF filename IS NOT NULL THEN
        IF :FILE_TYPE = 'I' THEN
            :FILE_NAME := :DOC.DOC_NO || '_' || :DOC.REC_COUNT || '_' || :DOC.SR_NO || '.JPG';
            HOST('cmd /c copy ' || filename || ' ' ||
            '\\172.16.1.0\share\DETAIL\' ||
            :DOC.DOC_NO || '_' || :DOC.REC_COUNT || '_' || :DOC.SR_NO || '.JPG' || ' /Y');
        ELSIF :FILE_TYPE = 'E' THEN
            TYP := SUBSTR(filename, INSTR(filename, '.'));
            :FILE_NAME := :DOC.DOC_NO || '_' || :DOC.REC_COUNT || '_' || :DOC.SR_NO || TYP;
            HOST('cmd /c copy ' || filename || ' ' || '\\172.16.1.0\share\DETAIL\' || ... || TYP || ' /Y');
        END IF;
        IF NOT Form_Success THEN
            Message('Error ___CLINE_1___
ELSE
Message('Upload Success.');
            COMMIT;
        END IF;
    END IF;
EXCEPTION
    WHEN OTHERS THEN
    message(dbms_error_Text);
END;

This code looks reasonable but has multiple serious bugs. Let’s fix them one by one.

7 Critical Bugs in Most Examples

Bug 1: Unquoted Paths (Spaces Break Everything)

The HOST command passes a string to the operating system. If any path contains spaces (like C:\My Documents\file.jpg), the OS interprets C:\My as the filename and Documents\file.jpg as a separate argument. The copy fails silently.

Fix: Wrap all paths in double quotes:

HOST('cmd /c copy "' || filename || '" "\\server\share\' || target || '" /Y');

Bug 2: INSTR(filename, ‘.’) Finds the FIRST Dot

For a path like C:\v1.2\report.pdf, INSTR(filename, ‘.’) returns the position of the dot in v1.2, giving you .2\report.pdf as the “extension.” This is clearly wrong.

Fix: Use INSTR(filename, ‘.’, -1) to search from the end of the string:

TYP := SUBSTR(filename, INSTR(filename, '.', -1));

Bug 3: Form_Success Does NOT Reflect HOST Results

This is the biggest myth in Oracle Forms development. Oracle’s documentation explicitly states:

“FORM_SUCCESS will return FALSE if the command fails for any reason (unless you’re on Windows 95 in which case it will still return TRUE)”

Even on modern Windows, HOST launches an external process asynchronously. Form_Success often returns TRUE even when the copy fails. Your “success” message is unreliable.

Fix: Don’t rely on Form_Success. Instead, verify the file exists after the copy:

-- After HOST command, check if target exists
HOST('cmd /c if exist "\\server\share\' || target || '" (echo FOUND) else (echo MISSING) > temp_check.txt');
-- Or better: use WebUtil's FILE_EXISTS

Bug 4: No File Type Validation

Users can select any file type. If the form expects a JPG but the user selects an EXE, the code blindly copies it. This is a security risk.

Fix: Validate the extension before copying:

v_ext := UPPER(SUBSTR(v_source_file, INSTR(v_source_file, '.', -1)));
IF v_ext NOT IN ('.JPG', '.JPEG', '.PNG', '.PDF') THEN Message('Invalid file type. Please select JPG, PNG, or PDF.');
RETURN;

END IF;

Bug 5: Silent Overwrites with /Y

The /Y flag overwrites existing files without prompting. If two records generate the same filename, data is lost.

Fix: Remove /Y or add a timestamp/sequence to filenames:

v_target := v_base_name || '_' || TO_CHAR(SYSDATE, 'YYYYMMDDHH24MISS') || v_ext;

Bug 6: No Error Handling for Network Failures

If the network share is unreachable, HOST may hang for 30+ seconds before timing out. The user sees a frozen screen with no explanation.

Fix: Use a wrapper script with timeout, or check connectivity first:

HOST('cmd /c ping -n 1 -w 1000 \\server > nul && copy ...');

Bug 7: Duplicated Message() Calls

In Oracle Forms, calling Message() once puts the text on the status bar. Calling it twice displays a modal alert box. While this works, it’s a quirk that confuses maintainers.

Fix: Use Message() twice intentionally (with a comment), or use Alert for proper dialogs.

The Fixed, Production-Ready Code

Here’s the complete trigger with all fixes applied. Block and item names have been changed to generic ones for reusability.

-- TRIGGER: WHEN-BUTTON-PRESSED on block UPLOAD_CTRL
-- PURPOSE: Copy a user-selected file to a network share with proper validation
DECLARE
    -- File paths
    v_source_file     VARCHAR2(500);
    v_target_file     VARCHAR2(500);
    v_target_path     VARCHAR2(500);
    v_extension       VARCHAR2(20);
    -- Record identifiers (adjust to your block names)
    v_doc_id          VARCHAR2(50)            := :UPLOAD_CTRL.DOC_ID;
    v_rec_count       VARCHAR2(10)            := :UPLOAD_CTRL.REC_COUNT;
    v_seq_no          VARCHAR2(10)            := :UPLOAD_CTRL.SEQ_NO;
    v_file_type       VARCHAR2(5)             := :UPLOAD_CTRL.FILE_TYPE;
    -- Network share base path (define once)
    c_network_share   CONSTANT VARCHAR2(200)  := '\\192.168.1.100\share\UPLOADS\';
    -- Allowed extensions
    TYPE t_ext_list IS TABLE OF VARCHAR2(10);
    v_allowed_exts    t_ext_list              := t_ext_list('.JPG', '.JPEG', '.PNG', '.PDF');
    -- Flag for validation
    v_ext_valid       BOOLEAN                 := FALSE;
BEGIN
    -- ============================================
    -- STEP 1: Let user select a file
    -- ============================================
    -- For Forms 6i (client-server): GET_FILE_NAME
    -- For Forms 10g+ (web): Use CLIENT_GET_FILE_NAME with WebUtil
    v_source_file := GET_FILE_NAME(File_Filter => 'Images and PDFs|*.jpg;*.jpeg;*.png;*.pdf|All Files|*.*|');
    -- Handle user cancellation
    IF v_source_file IS NULL THEN
        Message('No file selected. Operation cancelled.');
        RETURN;
    END IF;
    -- ============================================
    -- STEP 2: Extract and validate file extension
    -- ============================================
    -- Use LAST dot, not first (fixes Bug #2)
    v_extension := UPPER(SUBSTR(v_source_file, INSTR(v_source_file, '.', -1)));
    -- Validate extension
    FOR i IN 1..v_allowed_exts.COUNT LOOP
        IF v_extension = v_allowed_exts(i) THEN
            v_ext_valid := TRUE;
            EXIT;
        END IF;
    END LOOP;
    IF NOT v_ext_valid THEN
        Message('Invalid file type: ' || v_extension);
        Message('Allowed types: JPG, JPEG, PNG, PDF');
        RETURN;
    END IF;
    -- ============================================
    -- STEP 3: Build target filename based on FILE_TYPE
    -- ============================================
    -- This example forces .JPG for images (FILE_TYPE = 'I')
    -- Adjust the CASE statement to match your business rules
    IF v_file_type = 'I' THEN
        -- Force JPG extension for images
        v_target_file := v_doc_id || '_' || v_rec_count || '_' || v_seq_no || '.JPG';
    ELSIF v_file_type = 'E' THEN
        -- Keep original extension
        v_target_file := v_doc_id || '_' || v_rec_count || '_' || v_seq_no || v_extension;
    ELSIF v_file_type = 'P' THEN
        -- Force PDF extension
        v_target_file := v_doc_id || '_' || v_rec_count || '_' || v_seq_no || '.PDF';
    ELSE
        Message('Invalid FILE_TYPE: ' || v_file_type);
        RETURN;
    END IF;
    v_target_path := c_network_share || v_target_file;
    -- ============================================
    -- STEP 4: Copy the file (with proper quoting)
    -- ============================================
    -- Quote both paths to handle spaces (fixes Bug #1)
    -- Use cmd /c to execute and return
    HOST('cmd /c copy "' || v_source_file || '" "' || v_target_path || '"');
    -- ============================================
    -- STEP 5: Update form field and commit
    -- ============================================
    :UPLOAD_CTRL.FILE_NAME := v_target_file;
    -- Show success message (twice for modal display)
    Message('Upload successful: ' || v_target_file);
    Message('Upload successful: ' || v_target_file);
    COMMIT;
EXCEPTION
    WHEN OTHERS THEN
    -- Log and display error
    Message('Error during file copy: ' || DBMS_ERROR_TEXT);
    Message('Error during file copy: ' || DBMS_ERROR_TEXT);
    -- Optional: ROLLBACK;
END;

The Form_Success Myth: Why Your Error Check Is Broken

Many forum posts claim you can check if HOST succeeded using IF NOT Form_Success THEN. This is wrong in most cases.

Oracle’s official documentation confirms:

“On Windows 95 platforms, the FORM_SUCCESS built-in always returns TRUE for failed HOST commands. This includes calls to command.com or OS functions, any 16-bit DOS or GUI application, or invalid commands.”

Even on Windows NT and later, HOST runs asynchronously. Form_Success reflects whether the command was launched, not whether it completed successfully.

How to Actually Verify Success

You have three options:

Option 1: Check File Existence with WebUtil (Best for  Oracle Forms 10g+)

plsql

IF WEBUTIL_FILE.FILE_EXISTS(v_target_path, 'SERVER') THEN

Message('File copied successfully.');

ELSE

Message('File copy failed.');

END IF;

Option 2: Use a Temp File as a Flag

plsql

-- Create a temp file only if copy succeeds

HOST('cmd /c copy "' || v_source || '" "' || v_target || '" && echo SUCCESS > ' || v_temp_flag);

-- Then read the temp file to check

Option 3: Wwe Batch File with Exit CodeCreate a .bat file that returns an error level, then use HOST to run it and check Form_Success on the batch result.

Modern Alternatives: WebUtil and Beyond

CLIENT_GET_FILE_NAME (WebUtil)

For web-deployed Forms (10g, 11g, 12c), replace GET_FILE_NAME with:

v_source_file := CLIENT_GET_FILE_NAME(File_Filter => 'All Files |*.*|');

This requires WebUtil to be properly configured in your environment. You need:

  1. webutil.pll attached to your form
  2. webutil.olb in your Object Groups
  3. frmwebutil.jar in your CLASSPATH
  4. WEBUTIL_CONFIG environment variable pointing to webutil.cfg

WEBUTIL_FILE_TRANSFER.CLIENT_TO_AS

This WebUtil procedure transfers files directly from client to application server without HOST:

plsql

WEBUTIL_FILE_TRANSFER.CLIENT_TO_AS(

client_file => v_source_file,

server_file => v_target_file,

transfer_type => WEBUTIL_FILE_TRANSFER.TRANSFER_TYPE_BINARY

);

This is more reliable than HOST because it returns proper error codes and doesn’t rely on OS commands.

When to Use HOST vs. WebUtil

Scenario Recommendation
Forms 6i (client-server) GET_FILE_NAME + HOST
Forms 10g+ (web) with WebUtil CLIENT_GET_FILE_NAME + CLIENT_HOST
Forms 10g+ without WebUtil Cannot access client filesystem
Large files (>10 MB) WebUtil (better error handling)
Production security matters WebUtil (no command injection risk)

Security Considerations

Command Injection Risks

The HOST built-in executes OS commands. If any part of the command string comes from user input (like a filename), an attacker could inject additional commands.

Example attack: User names a file “file.jpg” & del C:\*.* & “This could delete files on the server.

Mitigation:

  • Never trust user input in HOST commands
  • Quote and escape all paths
  • Prefer WebUtil which doesn’t use OS commands

UNC Path Permissions

The Oracle Forms process must have:

  • Read access to the source file (client machine)
  • Write access to the network share

If permissions are missing, the copy fails silently.

Always validate the file extension before copying. Don’t rely on the file dialog filter—users can override it.

Common Mistakes and Edge Cases

Mistake Fix
Spaces in filename Quote paths: ‘”‘ || filename || ‘”‘
Extension extraction INSTR(filename ‘.’ -1) for last dot
Network share down Add timeout or ping check
Zero-byte file Validate DBMS_LOB.GETLENGTH or file size
Unicode filename Use NLSLANG setting or WebUtil
Very long paths (>260 chars) Windows limit; use shorter names
Client without cmd.exe Use WebUtil or Unix-specific commands

Frequently Asked Questions (FAQ)

Q1: How Upload File using Oracle forms with Shared Drive?

Q2: How do I handle filenames with spaces?Quote the path in the HOST command: ‘”‘ || filename || ‘”‘.

Q3: What’s the correct way to get file extension or file picker in oracle forms? SUBSTR(filename, INSTR(filename, ‘.’, -1)) — uses the last dot.

Q4: Can I use GET_FILE_NAME in web-deployed Forms? No. Use CLIENT_GET_FILE_NAME from WebUtil instead.

Q5: Is HOST safe ?No, not without strict input validation. Command injection is possible. Prefer WebUtil.

Q6: How do I prevent overwriting existing files?Remove the /Y flag, or append a timestamp to filenames.

Q7: What if the network share is unreachable?HOST may hang. Use CLIENT_HOST with WebUtil (non-blocking) or add a ping check.

Q8: Can I upload files larger than 10 MB?HOST works but blocks the UI. WebUtil’s CLIENT_TO_AS is better for large files.

Key Takeaways

  • GET_FILE_NAME works in 6i but searches the server in 10g+ unless using WebUtil
  • Form_Success is unreliable with HOST — always verify results separately
  • Quote paths to handle spaces in filenames
  • Use INSTR(filename, ‘.’, -1) for correct extension extraction
  • WebUtil is the modern replacement for web-deployed Forms
  • Validate file types before copying

Conclusion & Next Steps

Copying files in Oracle Forms to remote location you can follow this guide full and code.

For web deployments, migrate to WebUtil’s CLIENT_GET_FILE_NAME and WEBUTIL_FILE_TRANSFER.CLIENT_TO_AS. Yes, it requires configuration, but it’s the only supported path for client file access in Forms 10g and later.

Previous