Saturday, October 11, 2025

SQL*Developer Extension for VS Code Internal Key Corruptions

What does this look like?

These Key Corruptions can appear in different ways:

Note: The names for these screen based UI objects is taken from "visualstudio.com":

How to Confirm Key Corruptions?

In VS Code:
  1. Go to Output View in the Panel
  2. Select the "SQL Developer –Log" View Option
  3. Find a "Duplicate Key" Error Message.
"error": { 
"errorCode": "DBTU-02500", 
"message": "An unexpected condition occurred that prevented the request from being fulfilled", 
"cause": "An unexpected error with the following message occurred: Duplicate key PPLP_DR,PPLP_DR.WORLD (attempted merging values (...))", 
"action": "Retry the request, if the issue persists, report it to product support" 
}

How to Repair

  1. Go to "C:\Users\NBKRRCR\AppData\Roaming\DBTools\connections". 
  2. Locate the Key Name in the Output Panel above. 
  3. There should be 2 folders with the Key Name
    1. KeyName 
    2. KeyName.old 
  4. Shutdown VS Code 
  5. Rename the 2 folders with the Key Name
    1. KeyName --> KeyName.temp 
    2. KeyName.old --> KeyName 
  6. Restart VS Code 
  7. Repeat until no "Duplicate Key" error. 
  8. Move/Remove ".temp" folders. 

Wednesday, October 9, 2024

Oracle Connection to Docker Container Failed on Ubuntu 24.04

What Was the Problem?

After upgrading to Ubuntu 24.04, connections to an Oracle database in a Docker container failed.  These connections were working before the upgrade.

  • SQL*Plus: ORA-12637: Packet receive failed
  • "sqlnet.ora" (TRACE_LEVEL_CLIENT=user): Fatal NI connect error 12170
  • Oracle SQL Developer Extension for VSCode: Failed to connect

It Was Not AppArmor

I found many entries about Docker not starting after an Ubuntu upgrade.  While I don't know the root cause of this problem, no changes to AppArmor are needed to solve this problem.

What is the Interim Fix?

I found several fixes. I included links to websites.

SQL*Plus/SQL*Net:

Update "sqlnet.ora" File - Add "DISABLE_OOB=ON" to disable Out-of-Band communication.  Note: The location of the "sqlnet.ora" file can be based on the environment settings of ORACLE_HOME or TNS_ADMIN.

Oracle SQL Developer Extension for VSCode

Update "Advanced" Tab in "Update Connection" - Add a new name "oracle.net.disableOob" with a value of "true" to disable Out-of-Band communication.

What is the Root Cause?

I don't know.  I have not found it.  I assume there is a loss of functionality when Out-of-Band communication is not available for an Oracle client.  I will continue to follow this and add updates as I find them.

Friday, October 4, 2024

UPDATED: Unloading/Loading NLS (National Language Support) Data in Oracle

What is the problem?

Every Oracle database has 2 different character sets for "string" data types.  These character sets are defined whenever a database is created.

  • CHARACTER SET - This is the main character set for the database. It is set for specific environment and application needs.  This character set is normally used to store and handle all string data.
  • NATIONAL CHARACTER SET - This is the NLS (National Language Support) character set and is available for multi-lingual string data storage on all Oracle databases.  It can be set to one of these UNICODE character sets: "AL16UTF16" or "UTF8".
Oracle's DB Sample Schemas use the NLS character set for multi-lingual string data.  This data is loaded with SQL INSERT statements.  However, we have a need to unload and load this data to/from text files.

The problem is that text files will generally have string data for the database's main character set.  A different technique is needed to unload and load the NLS string data.  Oracle's DB Sample Schemas uses the UNISTR format to segregate NLS string data from string data that uses the database's main character set.

We will be using the UNISTR format as well.

How to Unload NLS String Data to a Text File?

The US7ASCII character set is a common subset of almost all main character sets for an Oracle database.  This is important because any NLS string data saved to a text file needs a common format with the database's main character set.  Also note the US7ASCII character set only uses the 7 LSBs (least significant bits) for each character.  Characters in this range can be found when Oracle's ASCII function returns decimal values between 0 and 127.  Additionally, the "\" character needs to be "escaped" with another "\" character.

We used the following function to encode database NLS string data to UNISTR format.  The resulting string data from this function will only contain US7ASCII characters and can be safely stored in a text file.  *UPDATE:* This function has been updated to accommodate "Supplementary characters ... high-surrogates ... and ... low-surrogates" as referenced in Oracle 21c Documentation  This multi-byte encoding was missing from the original post.  More documentation on this implementation is provided at ODBCapture Wiki Issue Z0034

Monday, September 23, 2024

SQL*Plus Stopped Working in Ubuntu 24 (Noble Numbat)

After the upgrade to Ubuntu 24 (Noble Numbat), Oracle's SQL*Plus stopped working and started throwing this error:

sqlplus: error while loading shared libraries: libaio.so.1: cannot open shared object file: No such file or directory

Many thanks to https://askubuntu.com/users/367548/user3032965 for solving this problem in the comment at https://askubuntu.com/a/1526423.  For ubuntu 24.04 and later, the name for libaio1 has changed!  The solution is to create a symbolic link from the new name to the old name:

sudo ln -s /usr/lib/x86_64-linux-gnu/libaio.so.1t64 /usr/lib/libaio.so.1

In my situation, "libaio1t64" was already installed.  SQL*Plus started working again after I created the symbolic link.

Friday, August 30, 2024

Native PL/SQL Application to Capture Source Code and Configuration Data

I recently completed development and testing on the open source project ODBCapture.

ODBCapture is a native PL/SQL application that can be used to capture self-building scripts (source code and configuration data) for a database.

Existing tools like TOAD, PL/SQL Developer, and SQL*Developer can create “source code” scripts from an Oracle database. They can also create data load scripts from an Oracle database. What they cannot do is create a cohesive set of installation scripts that execute from a single “install.sql” script.

Existing database source code is handled by Liquibase and Flyway which are “diff” engines. These “diff” engines simply track changes to a database. Rarely is the source code from these “diff” engines ever used to create a database from nothing. Typically, the database source code from these “diff” engines require some existing database to get started.

ODBCapture is not a “diff” engine. ODBCapture is unique in its ability to create Oracle database installation scripts that can create different “flavors” of Oracle databases from a common set of source code. This installation occurs after an initialization to an empty database or PDB, such as:

  • Create Database …
  • Create Pluggable Database …
  • Drop Schema …

The published website is https://odbcapture.org

ODBCapture has been successfully tested on these platforms (Click the link).

ODBCapture has been successfully tested on these database object types:

  • Advanced Queue
  • Advanced Queue Table
  • Context
  • Database Link
  • Database Trigger
  • Directory
  • Foreign Key (psuedo-object)
  • Grant, Database Object (psuedo-object)
  • Grant, System Privilege (psuedo-object)
  • Host ACL (psuedo object)
  • PL/SQL Function
  • Java Source
  • Index
  • Materialized View
  • Materialized View Index
  • Materialized View Foreign Key
  • Materialized View Trigger
  • Package Body
  • Package Specification
  • PL/SQL Procedure
  • RAS ACL (psuedo-object)
  • Role
  • Scheduler Job
  • Scheduler Program
  • Scheduler Schedule
  • Sequence
  • Schema Trigger
  • Synonym
  • Table
  • Table Index
  • Table Foreign Key
  • Table Trigger
  • Type Body
  • Type Specification
  • User
  • View
  • View Foreign Key
  • View Trigger
  • Wallet ACL (psuedo-object)
  • XDB ACL (psuedo-object)

ODBCapture has been successfully tested on these database data types:

    • BLOB
    • CHAR
    • CLOB
    • DATE
    • INTERVAL_DAY_TO_SECOND
    • JSON
    • NUMBER
    • RAW
    • TIMESTAMP
    • TIMESTAMP_WITH_LOCAL_TZ
    • TIMESTAMP_WITH_TZ
    • VARCHAR2
    • XMLTYPE


    Monday, August 19, 2024

    GitHub Pages Jekyll Theme Google Analytics Update

     Let's breakdown that title:

    • GitHub Pages - a website hosting feature in GitHub
    • Jekyll Theme - a static site generator with built-in support for GitHub Pages.
    • Google Analytics Update - Google Analytics 4 is the next generation of Analytics which collects event-based data from both websites and apps
    If you are using Jekyll Themed GitHub Pages with Google Analytics and haven't found the simplest way to convert it from Universal Analytics to GA4, this is your "how to"...

    Jekyll Themes


    Universal Analytics was a simple setup before GA4.  The "_config.yml" included a "google_analytics:" location where the Universal Analytics ID would activate the needed website changes to begin data collection.  With GA4 the new Measurement ID replaces the Universal Analytics ID.  However, the website activation is different for GA4.  Fortunately, the creators of Jekyll Themes included a place to update this new website activation.

    Head Custom Google Analytics


    GutHub Pages has several supported Jekyll Themes.  Each of these themes has an "_includes/head-custom-google-analytics.html" file.

    Within the "_includes/head-custom-google-analytics.html" file is the website activation code:
    {% if site.google_analytics %}
      <script>
        (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
        (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
                m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
            })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
        ga('create', '{{ site.google_analytics }}', 'auto');
        ga('send', 'pageview');
      </script>
    {% endif %}
        
    That code needs to be changed to the new data collection script:
    {% if site.google_analytics %}
      <!-- Google tag (gtag.js) -->
      <script async src="https://www.googletagmanager.com/gtag/js?id={{ site.google_analytics }}"></script>
      <script>
        window.dataLayer = window.dataLayer || [];
        function gtag(){dataLayer.push(arguments);}
        gtag('js', new Date());
        gtag('config', '{{ site.google_analytics }}');
      </script>
    {% endif %}
        

    Call Tree


    The "_includes/head-custom-google-analytics.html" file is called from the "_includes/head-custom.html" file by this line:
    {% include head-custom-google-analytics.html %}
    The "_includes/head-custom.html" file is called from the "_layouts/default.html" file by this line:
        {% include head-custom.html %}
    The "_layouts/default.html" file is the top level template in each Jekyll Theme.

    Procedure

    1. Create an "_includes" folder in the same folder as the "_config.yml" file.
    2. Copy the "_includes/head-custom-google-analytics.html" file for the correct theme from the list above.
    3. Paste the "_includes/head-custom-google-analytics.html" file into the new "_includes" folder.
    4. Modify the contents of the new "_includes/head-custom-google-analytics.html" file as described above.
    5. Push the changes and wait for GitHub to refresh the website.
    6. Confirm the new Google Analytics code in the header of the HTML source.

    Friday, July 5, 2024

    Oracle Cloud Autonomous Database File Not Found for TLS Connection


    The Attempt:

    I created an Autonomous Database on Oracle Cloud.  I used TLS (protocol=tcps) to successfully connect from a Windows SQL*Plus Instant Client to the database on Oracle Cloud.  However, I was unable to connect from an Ubuntu (Gnome) SQL*Plus Instant Client to the database on Oracle Cloud.


    The Error:

    Each connection attempt from Ubuntu SQL*Plus Instant Client to the Autonomous Database on Oracle Cloud threw a "file not found" error.


    Troubleshooting:

    I ran a "trace" in "sqlnet.ora" and found many "file not found" errors, all seemed to be related to Wallet, SSL, and Certificate Store.  In the trace file, I found SQL*Net was looking for the Certificate Store in "/etc/pki/tls/cert.pem".


    The Solution:

    I did not configure a wallet.  TLS uses CA Certificates instead of PKI certificates.

    I found a single file (PEM bundle) in "/etc/ssl/certs/ca-certificates.crt".  This was confirmed at Ubuntu's Website: Ubuntu root CA certificate trust store location

    I could not find a configuration in SQL*Net to change the location of the Certificate Store from "/etc/pki/tls/cert.pem" to "/etc/ssl/certs/ca-certficiates.crt".

    I did find moscicki at GitHub had a Symbolic Link that I was missing.  After I created the symbolic link, I was able to make the TLS connection from Oracle Instant Client for Linux x86-64 Version 23.4.0.0.0 to an Autonomous Database on Oracle Cloud without a wallet.

    Run these as root in Ubuntu:

    mkdir /etc/pki/tls
    ln -s /etc/ssl/certs/ca-certificates.crt /etc/pki/tls/cert.pem

    Tuesday, July 2, 2024

    Git Clone GLIBCXX_3.4.29 Not Found on Xubuntu


    The Attempt:


    This was my first attempt to clone a Github repository on Xubuntu (XFCE Desktop) using VSCode. I did not have this problem with Ubuntu (Gnome Desktop).
    • VSCode Version
      Version: 1.90.2
      Commit: 5437499feb04f7a586f677b155b039bc2b3669eb
      Date: 2024-06-18T22:33:48.698Z
      Electron: 29.4.0
      ElectronBuildId: 9728852
      Chromium: 122.0.6261.156
      Node.js: 20.9.0
      V8: 12.2.281.27-electron.0
      OS: Linux x64 5.15.0-113-generic snap
    • Git Version
      root# git --version
      git version 2.34.1
    • XUbuntu Version
      root# lsb_release -a
      No LSB modules are available.
      Distributor ID: Ubuntu
      Description: Ubuntu 22.04.4 LTS
      Release: 22.04
      Codename: jammy

      root# dpkg -l '*-desktop' | grep ^ii | grep 'ubuntu-'
      ii xubuntu-desktop 2.241 amd64 Xubuntu desktop system

    The Error Message:


    I received an error that included the following:
    git clone https://github.com/USER/REPO.git /home/USER/github/REPO --progress
    /snap/core20/current/lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.29' not found (required by /lib/x86_64-linux-gnu/libproxy.so.1)
    (USER is my username and REPO is the repository name.)

    Troubleshooting:


    I searched Google and found a myriad of solutions that included:
    • Update from "snap20" to "snap22"
    • Remove/Reinstall VSCode
    • Modify "snapcraft.yaml"
    I confirmed my "snap22" library contained the needed GLIBCXX_3.4.29 module. However, I didn't like any of those solutions because they required some underlying "tweeking" that has caused trouble in the past.

    The Solution:


    I stumbled onto this solution accidentally, and I don't know why it works. Run these commands using the "Git Bash Terminal" in VSCode
    cd /home/USER/github
    git clone https://github.com/USER/REPO.git REPO --progress

    Thursday, June 13, 2024

    ORA-12637: Packet Receive Failed - From Windows

    What's the Problem?

    I was intermittently getting an "ORA-12637: Packet Receive Failed" from Windows on a local network.

    • Running an Oracle Client on Windows.
    • Connecting to an Oracle Database on my Local Network.

    What's the Fix?

    Add an entry for the database server into the Windows "host" file.

    I have a DHCP server that hands-out specific IPv4 addresses to each server.  I added the IPv4 address and hostname to the "C:\Windows\System32\drivers\etc\hosts" file.

    Why Does this Work?

    The mechanism that was supposed to resolve IP addresses from hostnames wasn't working correctly.

    How to Troubleshoot?

    1. Create a "C:\app\oracle\network\admin\sqlnet.ora" file with the following entries.  (My version 21.3 ORACLE_HOME is "C:\app\oracle")
    DIAG_ADR_ENABLED=off
    LOG_DIRECTORY_CLIENT=C:\app\oracle\network\log
    TRACE_DIRECTORY_CLIENT=C:\app\oracle\network\traces
    # Trace Levels: off (0), user (4), admin (10), support (16)
    TRACE_LEVEL_CLIENT=admin
    2. Attempt to connect to the database.

    3. Find a new trace file in "C:\app\oracle\network\traces" folder.

    4. I found the following lines in the new trace file "cli_13580.trc":
    (13580) [13-JUN-2024 11:59:26:485] nttbnd2addr: looking up IP addr for host: hostname1
    (13580) [13-JUN-2024 11:59:26:485] snlinGetAddrInfo: entry
    (13580) [13-JUN-2024 11:59:27:512] snlinGetAddrInfo: getaddrinfo() failed with error 11001
    (13580) [13-JUN-2024 11:59:27:512] snlinGetAddrInfo: exit
    (13580) [13-JUN-2024 11:59:27:512] nttbnd2addr:  *** hostname lookup failure! ***
    (13580) [13-JUN-2024 11:59:27:512] nttbnd2addr: exit
    5. After adding the "hosts" file entry and I no longer received the ORA-12637 error.

    Friday, February 23, 2024

    Synergy with Wayland Using Chromium

     This is a rather specific issue.

    • Running Synergy 1.11 on Ubuntu.
    • Sharing Keyboard/Mouse from Ubuntu to Other Computers.
    • Upgraded Ubuntu to 22.04.
    • Synergy stopped sharing.

    The problem wasn't the network or the configuration because
    • Synergy successfully connected from all clients to the server.
    • The server showed all Synergy clients successfully connected.

    The odd thing is Chromium.  If I start Chromium on the Ubuntu 22.04 server, the keyboard sharing starts working.  If I stop Chromium on the Ubuntu 22.04 server, the keyboard sharing stops working.  I also noticed the log messages on the Synergy client including "LANGUAGE DEBUG" warnings for every keystroke while the cursor was moved to the client.  I assume Chromium setup some debugging channel that Synergy was able to use.  (I did not research this.)

    Takeaway 1:

    The root cause of the problem appears to be the Ubuntu 22.04 switch to Wayland.  Synergy doesn't support Wayland, but there are plans:

    Takeaway 2:

    Synergy has an interim fix.  Don't use Wayland with Ubuntu...

    Thursday, February 15, 2024

    Unit Testing a Thick Database

    Why Unit Test a Database?

    In the Java (OO) world, unit testing specifically avoids testing persistence.  The persistence engine (database) is mocked so it doesn't interfere with the purity of the testing.  Also, Java (OO) purists attempt to remove all logic from the database.  However, we typically don't find such purity in practice.


    What is a Thick Database?

    A Thick Database is a database with lots of logic built-in.  Dulcian.com does a great job of explaining what it is and why it's useful.  In practice, we tend to see some logic implemented in the database for a variety of reasons.


    What is a Unit in the Database?

    Most references define a "unit" as something like the smallest bit of logic in a system.  For this discussion, "unit" will refer to an interface.  Interfaces in an Oracle database include the following:

    • Packages
      • Procedures (Public and Internal)
      • Functions (Public and Internal)
    • Procedures
    • Functions
    • Types with Methods
    • Tables
      • Check Constraints
      • DML Triggers
    • View Triggers
    • Session Triggers
    • Database Triggers

    Is a Unit Test Framework Required?

    No.  However, a unit test framework does allow easier integration with CI/CD.  Examples of database unit test frameworks include:

    Alternatively, here is a bare-bones package that is useful when a framework is not available.

    create package simple_ut
    as
        C_FALSE           constant number := -1;
        C_TRUE            constant number := 0;
        C_BRIEF_OUTPUT    constant number := 0;
        C_NORMAL_OUTPUT   constant number := 1;
        C_VERBOSE_OUTPUT  constant number := 2;
        g_output_mode              number := C_NORMAL_OUTPUT;
        procedure ut_announce
                (in_str         in varchar2);
        function ut_assert
                (in_test_name   in varchar2
                ,in_test_string in varchar2)
            return number;
        procedure ut_assert
                (in_test_name   in varchar2
                ,in_test_string in varchar2);
        procedure demo;
    end simple_ut;
    /

    create package body simple_ut
    as
        procedure ut_announce
                (in_str         in varchar2)
        is
        begin
            dbms_output.put_line('');
            dbms_output.put_line('========================================');
            dbms_output.put_line('=== ' || $$PLSQL_UNIT || ' ' || in_str);
        end ut_announce;
        function ut_assert
                (in_test_name   in varchar2
                ,in_test_string in varchar2)
            return number
        is
            l_result   number;
        begin
            execute immediate 'BEGIN'                        || CHR(10) ||
                              'if ' || in_test_string        || CHR(10) ||
                              'then'                         || CHR(10) ||
                                 ':n1 := ' || C_TRUE  || ';' || CHR(10) ||
                              'else'                         || CHR(10) ||
                                 ':n1 := ' || C_FALSE || ';' || CHR(10) ||
                              'end if;'                      || CHR(10) ||
                              'END;' using out l_result;
            return l_result;
        end ut_assert;
        procedure ut_assert
                (in_test_name   in varchar2
                ,in_test_string in varchar2)
        is
        begin
            if ut_assert(in_test_name, in_test_string) = C_TRUE
            then
                if g_output_mode != C_BRIEF_OUTPUT
                then
                    DBMS_OUTPUT.PUT_LINE(' -) PASSED: ' || in_test_name);
                    if g_output_mode = C_VERBOSE_OUTPUT
                    then
                        DBMS_OUTPUT.PUT_LINE('             Details: "' ||
                            replace(in_test_string,CHR(10),';') || '"' );
                    end if;
                end if;
            else
                DBMS_OUTPUT.PUT_LINE('*** FAILED: ' || in_test_name);
                DBMS_OUTPUT.PUT_LINE('             Details: "' ||
                    replace(in_test_string,CHR(10),';') || '"' );
            end if;
        end ut_assert;
        procedure demo
        is
        begin
            ut_assert('This test passes', '1 = 1');
            ut_assert('This test fails', '0 = 1');
        end demo;
    end simple_ut;
    /


    Where to start?

    1. Pick something to test, like a procedure in a package.
    2. Define a "No Data" Test Case for that procedure (nothing for the procedure to do).
    3. Create a Unit Test Package to contain you Unit Test code.
    4. Create a procedure in the Unit Test Package called "no_data_to_process".
    5. Write the "no_data_to_process" procedure to call the procedure (from step 1) with without any test data setup.
    6. Add "ut_assert" procedure calls from the "simple_ut" package to document results.
    7. Run the "no_data_to_process" procedure and check results in DBMS_OUTPUT.
    8. Add more tests.

    Are there any Tips or Tricks?

    1. As part of the Test Case, test the data setup (if any) before the "actual" unit test.
    2. Run the "actual" unit test in a separate procedure with a dedicated Exception Handler.
    3. Create Unit Test Procedures/Functions to load Test Data into a single record variable.
    4. Use the single record variable to INSERT Test Data into a table.
    5. Setup Date/Time sensitive data for each run of a Unit Test.
    6. Create additional test customers/locations/actors as needed to re-run unit tests.
    7. Capture Sequence Generator values after the "actual" unit test.
    8. Include testing of logs after the "actual" unit test.
    9. Cleanup Test Data only when necessary to re-run unit tests.
    10. Develop a complete Test Data Set with a variety of Test Cases setup and ready for testing.

    What is the downside?

    If the database logic is unstable (constantly changing), it is very difficult to maintain the unit tests.  One strategy is to Unit Test only the functionality that is stable.

    What is the Upside?

    Several obvious, but sometimes unexpected outcomes of unit testing:
    • Testing code that serves no purpose results in removal of useless code.
    • Fault insertion testing results in much better error messages and error recovery.
    • Thinking through unit test cases results in simplification of overall implementation.

    Wednesday, January 31, 2024

    Monitoring Blogger with UptimeRobot

    I use UptimeRobot to monitor this site. The free version of UptimeRobot includes:
    • Monitor 50 different URLs.
    • Check each URL every 5 minutes.
    • Monitor HTTP or HTTPS.
    • Test for keyword in response, with upper/lower case option.
    • Limit response times.
    • Send Email alert on failure.
    • Access to their comprehensive monitor dashboard.
    Note: I am not paid by UptimeRobot. I do find it really useful.

    It turns out Blogger is suspicious of servers at UptimeRobot.  The result reeks havoc when trying to test for a keyword on a Blogger page.  Instead of sending the expected page, Blogger sends something like this to UptimeRobot:

    Our systems have detected unusual traffic from your computer network.  This page checks to see if it&#39;s really you sending the requests, and not a robot.

    Obviously, UptimeRobot is a robot.  So, I need a work-around.

    I use the "Full Response" link in UptimeRobot to review the entire response from Blogger.
    1. Go to UptimeRobot
    2. Setup a monitor on a Blogger URL and have it fail.
    3. Click on the new monitor in the navigation stack on the left.
    4. Click on "Details" at the far right of the "Incidents" region at the bottom.
    5. A "Full Response" button may be at the top of the pop-up window (Sometimes, it's not there).
    6. Right-Click and copy the URL for that button.
    7. Use something like "curl" or "wget" to pull that file for review.  (Windows Defender won't allow a browser to download the file in that link.)
    Inside the contents of the "Full Response" file, I look for something unique to my Blogger page and use it for a keyword.   Yes, it technically is not loading a page from this site.  However, it does confirm Blogger is responding and it is sending something that is unique to this site.

    Why did I make this post?  Blogger changed the response page and all my keyword monitors started failing.  I need this page for notes if/when it happens again...

    Note: In order to keep things easy for UptimeRobot, I check all my URLs on a 4 hour interval.  Checking these URLs 6 times a day is plenty and it reduces the total load on this free service.

    Thank you UptimeRobot.

    Thursday, August 4, 2022

    Installing ORDS 22.2 and Oracle APEX 21.2 on WSL-2/Docker

    What are we installing?


    Is this a best practice?

    Oracle APEX Free Tier
    • To continue with this APEX/ORDS installation, an active Oracle Support Identifier is required to download the latest patch for recent APEX/ORDS releases.
    Oracle APEX 21.2 Patch
    Oracle Personal Database OnPremise


    What do we need?

    Container Name   WSL2/Ubuntu Path         Docker Path
    OraEE213         /opt/install_files       /opt/install_files
    TomCat9r0        /opt/install_files       /opt/install_files


    Note: There is an excellent reference at Oracle-Base that includes setup of ORDS 22.1 onward and a link to setup ORDS versions previous to 22.1.



    Overview:

    1. Windows Setup Files for Installation
    2. Ubuntu Setup Files for Installation
    3. Create a PDB
    4. Install APEX in the New PDB
    5. Patch APEX in the New PDB
    6. Install APEX Images on Tomcat
    7. Configure and Install ORDS for the PDB on Tomcat

    1) Windows Setup Files for Installation

    Move/Copy these files to C:\tmp
    • apex_21.2_en.zip
    • apex_p33420059_212_GENERIC.zip
    • ords-22.2.0.172.1758.zip


    2) Setup APEX/ORDS Files for Installation

    1. Start the Ubuntu App
    2. Run These Commands
    sudo su -
    apt install unzip
    mkdir /opt/install_files
    cd /opt/install_files
    #
    unzip /mnt/c/tmp/apex_21.2_en.zip
    mv apex apex212
    #
    unzip /mnt/c/tmp/apex_p33420059_212_GENERIC.zip
    mv 33420059 apex212/p33420059
    #
    mv apex212/images apex212_images
    cp -rv apex212/p33420059/images/* apex212_images/
    rm -rf apex212/p33420059/images
    #
    chown -Rv 54321:54321 apex212
    #
    mkdir ords222
    cd ords222
    unzip /mnt/c/tmp/ords-22.2.0.172.1758.zip


    3) Create a PDB

    1. Open Docker Desktop.
    2. Find the "OraEE213" container.
    3. Click the ">_" Icon (CLI) for that container to open a new window.
    4. Run "sqlplus / as sysdba" to startup SQL*Plus and connect to the database.
    5. Run the commands below in SQL*Plus:
    create pluggable database "AP212PDB"
       admin user "PDB_ADMIN" identified by "PDB_ADMIN"
       default tablespace users
          datafile '/opt/oracle/oradata/EE213CDB/AP212PDB/users01.dbf'
                   size 5M autoextend on
       FILE_NAME_CONVERT = ('pdbseed', 'AP212PDB')
       STORAGE UNLIMITED TEMPFILE REUSE;

    alter pluggable database "AP212PDB" open;

    *NOTE:* To remove the new PDB run `drop pluggable database "AP212PDB" including datafiles;`


    4) Install APEX in the New PDB

    Login to the Docker Container that is running the Oracle EE 21.3 Database.
    1. Open Docker Desktop.
    2. Find the "OraEE213" container.
    3. Click the ">_" Icon (CLI) for that container to open a new window.
    4. Run "cd /opt/install_files/apex212" to move into the apex folder.
    5. Run "sqlplus / as sysdba" to startup SQL*Plus and connect to the database.
    6. Run the commands below in SQL*Plus:
    alter session set container = AP212PDB;

    set serveroutput on size unlimited format wrapped

    @apxsilentins.sql "SYSAUX" "SYSAUX" "TEMP" "/apex212_images/" \
      "Passw0rd!" "Passw0rd!" "Passw0rd!" "Passw0rd!"

    select status, owner, count(*)
     from  dba_objects
     where owner in ('APEX_210200', 'FLOWS_FILES', 'APEX_LISTENER')
     group by status, owner
     order by status, owner;

    alter user APEX_210200 identified by "Passw0rd!" account unlock;


    NOTE: apxsilentins.sql values:
    • SYSAUX - Default Tablespace for APEX application user
    • SYSAUX - Default Tablespace for APEX file user
    • TEMP - APEX Temporary Tablespace for Tablespace Group
    • /apex212_images/ - Virtual Directory in Tomcat for APEX Images"
    • Passw0rd! - APEX Public User Account
    • Passw0rd! - APEX Listener Account
    • Passw0rd! - APEX REST Public User Account
    • Passw0rd! - APEX Internal Administrator User Account

    5) Patch APEX in the New PDB

    Login to the Docker Container that is running the Oracle EE 21.3 Database.
    1. Open Docker Desktop.
    2. Find the "OraEE213" container.
    3. Click the ">_" Icon (CLI) for that container to open a new window.
    4. Run "cd /opt/install_files/apex212/p33420059" to move into the apex folder.
    5. Run "sqlplus / as sysdba" to startup SQL*Plus and connect to the database.
    6. Run the commands below in SQL*Plus:
    alter session set container = AP212PDB;

    set serveroutput on size unlimited format wrapped

    @catpatch.sql


    6) Install APEX Image Files on Tomcat

    1. Open Docker Desktop.
    2. Find the "TomCat9r0" container.
    3. Click the ">_" Icon (CLI) for that container to open a new window.
    4. Run "cd /opt/install_files/apex212_images" to move into the APEX Images folder.
    5. Run "cp -rv . "${CATALINA_HOME}/webapps/apex212_images""
    6. Confirm images are working using http://127.0.0.1:8080/apex212_images/apex_ui/img/apex-logo.svg.  A red oval with the work APEX should appear in the browser.


    7) Configure and Install ORDS for the PDB on Tomcat

    After I published this BLOG, I re-ran the scripts.  I found errors and missing information.  I will update as soon as possible.
    1. Open Docker Desktop.
    2. Find the "TomCat9r0" container.
    3. Click the ">_" Icon (CLI) for that container to open a new window.
    4. Run the commands below:
    export PATH="$PATH:/opt/install_files/ords222/bin"

    exec /bin/bash

    export ORDS_CONFIG=/opt/ords222_config

    mkdir "${ORDS_CONFIG}"

    cd "${ORDS_CONFIG}"

    ords install \
      --log-folder      /opt/ords222_config/logs \
      --feature-db-api  true \
      --admin-user      SYS \
      --db-hostname     OraEE213 \
      --db-port         1521 \
      --db-servicename  AP212PDB \
      --db-user         ORDS_PUBLIC_USER \
      --feature-rest-enabled-sql true \
      --feature-sdw     true \
      --gateway-mode    proxied \
      --gateway-user    APEX_PUBLIC_USER \
      --proxy-user      \
      --password-stdin  <<EOF
    OraEE213#!
    Passw0rd!
    Passw0rd!
    EOF

    ords config set security.verifySSL false

    ords war ords222_ap212pdb.war

    cp ords222_ap212pdb.war "${CATALINA_HOME}/webapps/"

    • Test Oracle APEX URL:
      • Paste "http://localhost:8080/ords222_ap212pdb" into a Browser
      • Workspace: INTERNAL
      • Username: ADMIN
      • Password: Passw0rd!
      • The APEX Administrator Page should appear
    • Test Web Based SQL*Developer:
      • Paste "http://localhost:8080/ords222_ap212pdb/sql-developer" into a Browser
      • Enter a Database User Name when prompted.
      • Enter a Database User Password when prompted.
      • The "Database Actions | Launchpad" page should appear.
    • REST Enable a Database Object:
      • Login to APEX as an APEX Developer.
      • Open the SQL Workshop.
      • Select Object Browser.
      • Select a table.
      • Click on the REST tab
      • "Rest Enable Object": YES
      • "Authentication Required": NO
      • Click on APPLY
      • Copy the RESTful URL
      • Past the URL into a Web Browser
      • A JSON document should return

    Removal

    1. Remove ORDS from Tomcat
    2. Unplug the PDB

    1) Remove ORDS from Tomcat

    WARNING: This will remove the ORDS installation.  It will undo the work done in Step 7.

    rm -f "${CATALINA_HOME}/webapps/ords222_ap212pdb.war

    rm -rf "${CATALINA_HOME}/webapps/ords222_ap212pdb


    2) Unplug the new PDB

    WARNING: This will remove the PDB from the Database.  It will undo the work done in Step 3.

    alter pluggable database "AP212PDB" close immediate;

    alter pluggable database "AP212PDB" unplug
      into '/opt/oracle/oradata/EE213CDB/AP212PDB/AP212PDB.XML';

    drop pluggable database "AP212PDB" keep datafiles;

    zip -q ./AP212PDB_PDB.zip /opt/oracle/oradata/EE213CDB/AP212PDB/*

    rm -rf /opt/oracle/oradata/EE213CDB/AP212PDB/*

    Saturday, July 9, 2022

    Distributed (Offline) Issue (Bug) Tracker

    Git is one of the most popular source (version) control tools today.

    GitHub and GitLab are very popular hosting sites for Git Repositories.

    As a developer, I have come to appreciate Git's ability to continue using source control when there is no internet connection.  This is especially useful when travelling.

    Both GitHub and GitLab also have Wiki Pages.  These are very useful for documenting development procedures and other things that aren't included in product documentation.  Because GitHub and GitLab implement Wiki Pages in a Git Repository, the Wiki Repository can be downloaded and updated offline.

    Then there are the Issue Trackers. Both the GitHub Issue Tracker and GitLab Issue Tracker are only available online.  Since these Issue Trackers are used to guide and document software development, they need to be available during development activities.  However, neither of these Issue Trackers are available offline.

    The need for a distributed issue (bug) tracker is evident from the attention it is getting on the internet.  Several attempts have been made, but I have not been able to find anything stable and actively supported.

    To solve this problem, I created a Wiki Based Issue Tracker using the GitHub Issue Tracker and basic Linux/GNU tools (bash, awk, curl, sed, jq, ls, head, and date).  It includes a utility that will capture GitHub issues and convert them to Wiki Based Issues (designed for one-time conversion of all issues).



    Summary Report Screenshot (Partial)

    What prevents 2 developers from modifying the same issue?

    Nothing. Multiple developers can modify the same issue in the same way multiple developers can modify the same source code file in Git.  And, just like Git, the "merge" is where it all gets sorted.

    What about a Kanban Board?

    A basic issue reporting tool is provided.  This tool can be modified to create a Kanban Board style report.

    What about an interactive Kanban Board?

    Hmmm...

    Monday, January 17, 2022

    Installing Oracle Database and Tomcat on WSL-2/Docker

    What are we installing?
    • Windows Subsystem for Linux (WSL2)
    • Docker Desktop for Windows
    • Oracle Database
    • Tomcat Web Server
    What do we need?
    • Computer/Laptop
    • Windows 10 version 2004 and higher (Build 19041 and higher) or Windows 11
    • 16 Gb Memory Recommended
    Overview:
    • Setup Windows Subsystem for Linux (WSL2).
    • Setup Docker for Windows.
    • Load and Run a Docker Image that has an Oracle Database.
    • Load and Run a Docker Image that has a Tomcat WebApp Server.
    • Failed ORDS Docker Image with Failure Source Identified.

    Windows Subsystem for Linux (WSL2)

    This procedure was sourced from Microsoft.com: Install WSL:
    • Run CMD as Administrator
      • wsl -l -v
        • Should show "NAME STATE VERSION" heading with a line underneath showing "Ubuntu Running 2".  If not, run the "wsl --install" in the next step.
      • wsl --install -d Ubuntu
        • A reboot will be required to activate the installation.
        • The Ubuntu App will run automatically after reboot.
        • The Ubuntu App will create a new username and password. - The username and password created in the Ubuntu App is specific to each separate Linux distribution that you install under WSL and has no relationship to your Windows user name.
        • If any problems, see Microsoft.com: installation-issues
      • wsl --shutdown - Run this if you need to shutdown WSL.
    • Start the Ubuntu App and Run These Commands
      • sudo apt update - Updates the list of packages available for Ubuntu.
      • sudo apt upgrade - Upgrades Ubuntu packages.
    • Review and Set advanced options as needed.  See Microsoft.com: Advanced settings configuration in WSL
    See also: Microsoft.com: Setup WSL for Development


    Docker Desktop for Windows

    • Go to Docker.com: Docker Desktop
    • Click on "Download for Windows"
    • Run "Docker Desktop Installer.exe"
    • Open Docker Desktop
      • "Settings" --> "Resources" --> "WSL Integration"
      • Turn on "ubuntu" for "enable integration with additional distros:"
      • Apply & Restart
    • Run Ubuntu App
      • (Optional) docker run hello-world

    Oracle Database

    This procedure will persist the database files outside of the Docker container at "/opt/OraEE213/oradata" in WSL2/Ubuntu.  After the database is created, it will re-open with all saved changes if the Docker container is restarted.
    • Open the Ubuntu App and Run These Commands:
    sudo mkdir /opt/OraEE213/oradata

    sudo chown 54321 /opt/OraEE213/oradata

    docker network create oranet

    docker login container-registry.oracle.com

    docker pull container-registry.oracle.com/database/enterprise:21.3.0.0

    docker run -d --restart unless-stopped --network=oranet -p 1521:1521 -p 5500:5500 -e ORACLE_SID=EE213CDB -e ORACLE_PDB=TESTPDB -e 'ORACLE_PWD=OraEE213#!' -v /opt/OraEE213/oradata:/opt/oracle/oradata -v /opt/install_files:/opt/install_files --name OraEE213 container-registry.oracle.com/database/enterprise:21.3.0.0
    • Run Docker Desktop
      • Select "Containers/Apps" in the menu list on the left.
      • Click on the "Logs" Icon in the "OraEE213" container line.
      • The log of the database installation will appear.
      • Wait for this banner before attempting to use the database:

    #########################

    DATABASE IS READY TO USE!

    #########################

      • (Optional) Click the ">_" Icon (CLI) on the "OraEE213" container line and run "sqlplus / as sysdba" to login to the container database as "SYS".
      • (Optional) Connect to the container database from an Oracle client using the connect string "//localhost:1521/EE213CDB" and "system/OraEE213#!" login.
      • (Optional) Connect to the pluggable database from an Oracle client using the connect string "//localhost:1521/TESTPDB" and "system/OraEE213#!" login.
      • (Optional) Check OEM DB Express at url https://localhost:5500/em/login, Username: SYSTEM, Password: OraEE213#!, Container Name: (Blank)

    Tomcat Web Server

    • Open the Ubuntu App and Run This Command
      • docker run -d --restart unless-stopped --network=oranet -p 8080:8080 -v /opt/TomCat9r0/webapps:/usr/local/tomcat/webapps -v /opt/install_files:/opt/install_files --name TomCat9r0 tomcat:9.0
    • Run Docker Desktop
      • Select "Containers/Apps" in the menu list on the left.
      • Click the ">_" Icon (CLI) on the "TomCat9r0" container line.
      • Run these commands:
    cp -rf "/usr/local/tomcat/webapps.dist"/* "/usr/local/tomcat/webapps"

    sed "-i_bak" -e '$s?^</tomcat-users>$?<role rolename="manager-gui"/><user username="manager" password="tomcat" roles="manager-gui"/></tomcat-users>?1' "/usr/local/tomcat/conf/tomcat-users.xml"

    sed "-i_bak" -e '/RemoteAddrValve/d' -e '/0:0:0:0:0:0:0:1/d' "/usr/local/tomcat/webapps/manager/META-INF/context.xml"

    sed "-i_bak" -e '/RemoteAddrValve/d' -e '/0:0:0:0:0:0:0:1/d' "/usr/local/tomcat/webapps/host-manager/META-INF/context.xml"
    • (Optional) Go to "http://localhost:8080/"
      • Click on "Manager App" button
      • Login with Username "manager" and password "tomcat"
      • Confirm Tomcat Web Applications are available and working.

    Next Post: Installing ORDS and Oracle APEX

    In the next post "Installing ORDS and Oracle APEX on WSL-2/Docker", we look at installing ORDS and Oracle APEX

    Addendum: Failed ORDS Docker image

    An alternative to the Tomcat installation is using Oracle's ORDS Dockerfile to create a Docker Container with ORDS.  However, there are 2 problems with this alternative:
    1. There is a bug in Oracle's Dockerfile (shown below).
    2. Multiple Docker Containers are required for each ORDS deployment.  Each deployment of ORDS requires a different HTTP Port Number.  With Tomcat, all ORDS servers share the same HTTP Port Number.
    For the source of this section, see Oracle.com: Container Registry: "Database" --> "ords" --> "Oracle REST Data Services (ORDS) with Application Express"
    • Open the Ubuntu App and Run These Commands:
    sudo mkdir "/opt/ords21.4.0"

    echo 'CONN_STRING=SYS/OraEE213#!@//OraEE213:1521/TESTPDB' > "/tmp/conn_string.txt"

    sudo mv "/tmp/conn_string.txt" "/opt/ords21.4.0"

    docker run --rm --network=oranet -p 8181:8181 -v /opt/ords21.4.0:/opt/oracle/variables --name ords21.4.0 container-registry.oracle.com/database/ords:21.4.0
    • FAILS with this message:
    INFO : This container will start a service running ORDS 21.4.0 and APEX 21.2.0.
    INFO : CONN_STRING has been set as variable on container.
    INFO : Database connection established.
    INFO : Apex is not installed on your database.
    INFO : Installing APEX on your DB please be patient.
    INFO : If you need more verbosity run below command:
    docker exec -it b402760c75a3 tail -f /tmp/install_container.log
    INFO : APEX has been installed.
    INFO : Configuring APEX.
    INFO : APEX_PUBLIC_USER has been configured as oracle.
    INFO : APEX ADMIN password has configured as 'Welcome_1'.
    INFO : Use below login credentials to first time login to APEX service:
    Workspace: internal
    User: ADMIN
    Password: Welcome_1
    INFO : Preparing ORDS.
    INFO : Installing ORDS on you database.
    Requires to login with administrator privileges to verify Oracle REST Data Services schema.

    Connecting to database user: SYS as sysdba url: jdbc:oracle:thin:@////OraEE213:1521/TESTPDB
    2022-01-18T00:14:23.731Z WARNING Failed to connect to user: SYS as sysdba url: jdbc:oracle:thin:@////OraEE213:1521/TESTPDB
    IO Error: Invalid connection string format, a valid format is: "//host[:port][/service_name]" (CONNECTION_ID=DUId2GdqTiaf5/93oFpqsw==)

    java.sql.SQLRecoverableException: IO Error: Invalid connection string format, a valid format is: "//host[:port][/service_name]"  (CONNECTION_ID=DUId2GdqTiaf5/93oFpqsw==)
    INFO : Starting ORDS....
    2022-01-18T00:14:27.622Z WARNING     Failed to connect to user: ORDS_PUBLIC_USER url: jdbc:oracle:thin:@////OraEE213:1521/TESTPDB
    IO Error: Invalid connection string format, a valid format is: "//host[:port][/service_name]"  (CONNECTION_ID=Z2b/FsUxR1C7IzNDt5+RTQ==)

    Problem: The "/opt/oracle/ords/startService.sh" script in the container splits the $CONN_STRING value into DB_USER, DB_PASS, DB_HOST, DB_PORT, and DB_NAME variables.  The DB_HOST value retains the leading "//" in front of the hostname in the $CONN_STRING value.  The "//" is required for the database connection, but fails when used by ORDS.

    update: Changed "\" to "/" on database connect strings.