Posts from 2025

Dovecot 2.4.2 upgrade

Dovecot recently released version 2.4.2 which required some changes to the configuration file (from version 2.3.x).

I use Dovecot as a personal, local IMAP server which pulls from the corporate Outlook server so I can maintain a local archive not subject to any quota constraints.

As I use Arch Linux and mindlessly update weekly, I was puzzled when Thunderbird suddenly stopped working.

My Dovecot server is local for me only, insecure and hence my configuration file is relatively simple.

Here is my modified Dovecot configuration for 2.4.2.

dovecot_config_version = 2.4.2
dovecot_storage_version = 2.4.2

mail_driver = maildir
mail_path = ~/Maildir
mailbox_list_layout = fs
protocols = imap
listen = 127.0.0.1
auth_allow_cleartext = yes
auth_mechanisms = plain login
userdb passwd {
   driver = passwd
}
passdb pam {
    driver = pam
}

fun with static site generators

Table of Contents

  • Introduction
  • Test Environment
    • Hardware
    • Test Data
  • Hugo
  • Eleventy
  • BSSG
  • Zola
  • Nikola
  • Pelican
  • Jekyll
  • Useful SSG performance resources

Introduction

Static site generators (SSG's) are often used for blogs. SSG's typically process Markdown files into static HTML files. The use of static HTML files (rather than dynamically generating the site using a database) offers benefits for performance and security.

I use Hugo for my blog and have used (or experimented with) the following static site generators (SSG's).

  • Hugo (Go)
  • Eleventy (Javascript)
  • BSSG (Bash)
  • Zola (Rust)
  • Nikola (Python)
  • Pelican (Python)
  • Jekyll (Ruby)

A throwaway post from Neil Brown on Mastodon prompted me to investigate the build performance of different static site generators with a significant volume of posts (1,000).

Neil reduced the build time for his Hugo blog simply by adding more hardware resources. A decent strategy involving minimal effort producing an immediate improvement.

'I have upped the RAM in the VM running my Web server to a heady 1GB, and added a second CPU core'.

'That has halved the Hugo build time for my blog [from 4 minutes to 2 minutes]'.

This comment surprised me as I also use Hugo which builds my entire blog, containing 1,000 pages, in less than two seconds on a 10 year old desktop computer.

Neil's blog is self-hosted and uses Hugo. A 'View Source' reveals the version of Hugo in use. Neil is using v0.131.0 (released in August 2024).

<meta name="generator" content="Hugo 0.131.0">

The latest version of Hugo is 0.151.1 (released in October 2025). However, Neil is using the Hugo version included in the Debian (Trixie) repositories.

Reviewing the 'Archives' page, Neil's blog contains 457 posts.

Neil moved his blog from HTMLy to Hugo in 2023 and was using Hugo v.0.111.3 (from the Debian repos) back then and used the Etch theme.

Looking at the Etch theme, it is clear Neil has stuck with this attractive, minimal Hugo theme since then.

Given the disparity between Neil's build time and mine, I thought it would be fun to compare the performance of Hugo with different themes as well as other popular static site generators.

Test Environment

Hardware

  • Lenovo M900 Tower Desktop (SFF)
  • CPU: Intel i7-6700 CPU @ 3.40GHz (4 cores, 8 threads)
  • Memory: 48GB
  • Disk: 1TB
  • O/S: Linux 6.17.2

Test Data

I used my personal blog as the data set for the performance tests.

  • 1028 articles (Markdown)
  • Content spanning twenty years (2005 to 2025)
  • 116 code blocks
  • 74 static images
  • 29 categories
  • 46 tags

Hugo

Hugo: https://gohugo.io/

Hugo is a popular static site generator written in Go with a reputation for speed and performance.

$ hugo version
hugo v0.151.1+extended+withdeploy linux/amd64 BuildDate=unknown
$ go version
go version go1.25.3 X:nodwarf5 linux/amd64

The tests ran the standard 'hugo build' command three times and took the average elapsed time.

Theme Time (secs)
Ananke 0.615
PaperMod (Base) 1.067
PaperMod (Custom) 1.633
Etch (Base) 1.911
Etch (Related) 1.958
BearBlog 0.425
Simple 0.377
Beautiful Hugo 1.541

Most Hugo themes used the default, out of the box settings with no customisation.

The 'PaperMod (Custom)' test used my personal blog which includes additional 'Archive', 'Categories', 'Posts' pages and search functionality.

The timings for 'Etch' surprised me as it is a relatively simple theme that displays a list of all posts.

I added support for up to 15 'Related Posts' using Neil's code but saw no noticeable increase in build time (which is less than two seconds).

Hugo supports 'Related Posts' functionality and the list of articles is built during the build (regardless of whether it is used or not).

Ananke: https://github.com/theNewDynamic/gohugo-theme-ananke

PaperMod: https://github.com/adityatelange/hugo-PaperMod

Etch: https://github.com/LukasJoswiak/etch

BearBlog: https://github.com/janraasch/hugo-bearblog

Simple: https://github.com/maolonglong/hugo-simple/

Beautiful Hugo: https://github.com/halogenica/beautifulhugo

Hugo provides useful diagnostics about potential performance bottlenecks.

Here is the template metrics report for the Etch theme (with related posts). There are three candidate templates that could be cached (header, footer and posts).

$ hugo --templateMetrics --templateMetricsHints
Template Metrics:
     cumulative       average       maximum      cache  percent  cached  total
       duration      duration      duration  potential   cached   count  count  template
     ----------      --------      --------  ---------  -------  ------  -----  --------
   2.691672237s   53.833444ms   83.570806ms          0        0       0     50  rss.xml
   1.409607939s    1.345045ms   11.568865ms          0        0       0   1048  single.html
   322.542988ms      307.77µs    2.927895ms         28        0       0   1048  _partials/related.html
   126.863653ms      115.54µs    1.183336ms         44        0       0   1098  _partials/head.html
    81.827628ms   40.913814ms   41.042982ms        100        0       0      2  _partials/posts.html
    79.788949ms      25.193µs     363.218µs          0        0       0   3167  li.html
    55.705094ms    1.160522ms    7.457174ms          0        0       0     48  _default/taxonomy.html
    44.028022ms   44.028022ms   44.028022ms          0        0       0      1  index.html
    43.649693ms   43.649693ms   43.649693ms          0        0       0      1  list.html
    32.992786ms   32.992786ms   32.992786ms          0        0       0      1  sitemap.xml
     24.19536ms      22.035µs     948.957µs        100        0       0   1098  _partials/header.html
     7.410874ms       6.749µs     143.528µs        100        0       0   1098  _partials/footer.html
      961.219µs     106.802µs     278.188µs          0        0       0      9  _shortcodes/figure.html
      708.877µs     141.775µs     299.575µs          0        0       0      5  _markup/render-table.html.html
      551.337µs     110.267µs     208.377µs          0        0       0      5  _markup/render-table.rss.xml
      105.423µs      52.711µs      88.545µs          0        0       0      2  alias.html
       15.147µs      15.147µs      15.147µs          0        0       0      1  /css/dark.css
         1.76µs        1.76µs        1.76µs          0        0       0      1  404.html

Total in 2002 ms

Eleventy

Eleventy: https://www.11ty.dev/

Eleventy is a popular SSG written in Javascript.

Eleventy Base Blog (v9): https://github.com/11ty/eleventy-base-blog

The Eleventy Base Blog theme is minimal and not dissimilar in appearance from the Hugo PaperMod theme.

$ node --version
v20.19.5
$ npx @11ty/eleventy --version
3.1.2

Building the Eleventy blog. Eleventy doesn't have separate 'build' and 'serve' commands.

The Eleventy build summary for my blog.

$ npx @11ty/eleventy --serve
[11ty/eleventy-img] 143 images optimized (143 deferred)
[11ty] Benchmark   1664ms  11%  1052× (Configuration) "@11ty/eleventy/html-transformer" Transform
[11ty] Copied 5 Wrote 1043 files in 14.53 seconds (13.9ms each, v3.1.2)
[11ty] Server at http://localhost:8080/

Eleventy supports incremental builds using the '--incremental' parameter which only processes content modified since the last build.

Initially, I saw no difference using '--incremental' but the Eleventy documentation suggested adding the '--ignore-initial' option. This reduced the build time significantly from 14 seconds to sub-second.

$ npx @11ty/eleventy --serve --incremental --ignore-initial
[11ty] Copied 5 Wrote 0 files in 0.77 seconds (v3.1.2)
[11ty] Watching…
# Add a new post with tags
[11ty/eleventy-img] 3 images optimized (3 deferred)
[11ty] Wrote 32 files (skipped 1012) in 0.51 seconds (v3.1.2)
# Add more text to existing post
[11ty/eleventy-img] 3 images optimized (3 deferred)
[11ty] Wrote 32 files (skipped 1012) in 0.46 seconds (v3.1.2)

Summary of timings for Eleventy

Theme Time (secs)
Eleventy (Full) 14.42
Eleventy (Incremental) 0.46

BSSG

BSSG - https://bssg.dragas.net/

Bash Static Site Generator (BSSG) is an SSG created by Stefano Marinelli. BSSG is written in the Bash shell

BSSG is a relatively new SSG. The first public release of BSSG was in March 2025 but there have been 14 subsequent releases.

BSSG includes a broad range of themes, support for incremental builds, parallel processing and a post article editor to manage content

BSSG doesn't currently support 'Categories' so all existing 'Categories' were migrated to 'Tags'.

It is possible this skewed the data set slightly and adversely affected performance as it resulted in four tags having a lot of associated posts. BSSG can list all tags with article counts using the 'bssg.sh tags' command.

Tag Count
blogging 236
football 112
software 122
UK 260
$ bssg.sh
BSSG - Bash Static Site Generator (v0.32)
$ bash --version
GNU bash, version 5.3.3(1)-release (x86_64-pc-linux-gnu)

Initial BSSG build from scratch.

$ bssg.sh build

BBSG uses incremental builds and only rebuilds what has changed.

Theme Time (secs) Notes
Default 2,389 Full (2,389 secs = 39 mins)
Default 23 Unchanged.
Default 61 Add new post (no tags).
Default 100 Add new post (existing tag).
Default 62 Modify existing post.
Default 107 Add existing tag to existing post.
Default 83 Add new tag to existing post.

By default, BSSG generates related posts based on the 'Tags' in each post. The default number of related posts displayed is 3. If this feature is disabled, then the build time is reduced significantly.

Theme Time (secs) Notes
Default 169 Full
Default 12 Unchanged.
Default 63 Add new post (no tags).
Default 62 Add new post (existing tag).
Default 64 Modify existing post.
Default 62 Add existing tag to existing post.
Default 70 Add new tag to existing post.

BSSG also supports parallel processing using the GNU parallel shell tool. The GNU parallel package is very lightweight (< 1MB).

BSSG detects the presence of GNU parallel automatically and spawns N processes in parallel where N is the number of threads available.

Checked dependencies. Parallel available: true
GNU parallel found! Using parallel processing.

On my computer, this resulted in BSSG spawning 8 Bash processes which may have been too many as the load average climbed to between 10 and 15.

However, the elapsed time for the initial build of a blog with 1,000 posts reduces from 39 minutes to under 10 minutes.

Before you exclaim '10 minutes when Hugo and Eleventy are sub-second', think about how often you completely rebuild every single post on your blog. Not very often.

The typical use case is writing a new blog post. There may be occasions when you change theme or spend two weeks consolidating all your tags and categories but, hopefully, those should be relatively rare.

Theme Time (secs) Notes
Default 559 Full. Parallel.
Default 32 Unchanged.
Default 60 Add new post (no tags).
Default 75 Add new post (existing tag).
Default 67 Modify existing post.
Default 73 Add existing tag to existing post.
Default 67 Add new tag to existing post.

Removing 'Related Posts' and running in parallel reduces the time for a full build to 1 minute and an incremental build to 45 seconds.

Theme Time (secs) Notes
Default 59 Full. Parallel.
Default 30 Unchanged.
Default 44 Add new post (no tags).
Default 44 Add new post (existing tag).

One big advantage of BSSG is the ability to quickly and easily change themes. You simply select a theme, modify the THEME entry in the configuration file and it just works. This is because BSSG themes use a single CSS style sheet. This may limit the functionality available but it just works.

Zola

Zola - https://www.getzola.org/

Zola is a SSG written in Rust. Like Hugo, Zola is a single executable. Like Hugo, Zola is fast. Like Hugo, changing themes in Zola is not simply a case of modifying the THEME entry in 'config.toml'. Each theme seems to have additional, custom configuration options that need to be set.

$ zola --version
zola 0.21.0
$ rustc --version
rustc 1.90.0 (1159e78c4 2025-09-14) (Arch Linux rust 1:1.90.0-3)

Serene Theme - https://github.com/isunjn/serene

Building the blog

$ zola build

The Zola build time for 1,000 posts was so lightning fast, I had to check it actually worked !

$ zola build
Building site...
Checking all internal links with anchors.
> Successfully checked 0 internal link(s) with anchors.
-> Creating 1030 pages (0 orphan) and 1 sections
Done in 351ms.

Like Hugo, Zola also has a live development server that watches for changes to the site in real-time. This is also fast.

Building site...
Checking all internal links with anchors.
> Successfully checked 0 internal link(s) with anchors.
-> Creating 1031 pages (0 orphan) and 1 sections
Done in 309ms.

Listening for changes in zola-blog/{config.toml,content,sass,static,templates,themes}

Web server is available at http://127.0.0.1:1111 (bound to 127.0.0.1:1111)

Change detected @ 2025-10-14 13:17:09
-> Content changed zola-blog/content/posts/zola-new-post.md
Checking all internal links with anchors.
> Successfully checked 0 internal link(s) with anchors.
-> Creating 1031 pages (0 orphan) and 1 sections
Done in 283ms.

Finally I experimented with a couple more themes.

Linkita - https://www.getzola.org/themes/linkita/

BearBlog - https://www.getzola.org/themes/bearblog/

PaperMod - https://www.getzola.org/themes/papermod/

Theme Time (secs) Notes
Serene 0.35 Full
Serene 0.28 Incremental
Linkita 1.77 Full
Linkita 1.70 Incremental
Bearblog 0.26 Full
Bearblog 0.25 Incremental
PaperMod 20.70 Full
PaperMod 20.51 Incremental

Nikola

Nikola - https://getnikola.com/blog/

$ python -V
Python 3.13.7
$ nikola version
Nikola v8.3.3

Useful Nikola commands.

nikola build
nikola serve --browser
nikola auto

To force a full rebuild in Nikola, you need to remove the 'output' directory.

You also need to use the Linux time command to get the elapsed timings for the 'nikola build' command.

Nikola includes the wonderful blog.txt theme (originally written for Wordpress by Scott Wallick) so kudos to Nikola's author Roberto Alsina for that.

Theme Time (secs) Notes
Default 44.86 Full
Default 4.72 Unchanged
Default 5.86 Add new post (no tags).
Default 5.75 Add new post (existing tag).
Default 5.98 Modify existing post.
Default 5.87 Add existing tag to existing post.
Default 5.70 Add new tag to existing post.
blogtxt 47.34 Full
blogtxt 4.93 Unchanged
blogtxt 4.78 Add new post (no tags).
blogtxt 4.82 Add new post (existing tag).

Pelican

Pelican - https://getpelican.com/

Create a dedicated virtual environment for Pelican.

$ workon Pelican
(Pelican) $ python -V
Python 3.13.7
(Pelican) $ pelican --version
4.11.0

Pelican doesn't have separate build and server commands. You simply run the development server which builds the site and watches for any changes.

(Pelican) $ pelican --autoreload --listen
Serving site at: http://127.0.0.1:8000 - Tap CTRL-C to stop
Done: Processed 1034 articles, 0 drafts, 0 hidden articles, 0 pages,
0 hidden pages and 0 draft pages in 3.65 seconds.

Add a new post (incremental build).

-> Modified: pelican-blog/content/my-pelican-post.md.
re-generating...
Done: Processed 1035 articles, 0 drafts, 0 hidden articles, 0 pages,
0 hidden pages and 0 draft pages in 2.96 seconds.

Summary

Theme Time (secs) Notes
Default 3.65 Full
Default 2.96 Incremental

Jekyll

Ruby based blog.

$ ruby -v
ruby 3.4.6 (2025-09-16 revision dbd83256b1) +PRISM [x86_64-linux]
$ bundle exec jekyll -v
jekyll 4.4.1

Jekyll base theme (minima) - https://github.com/jekyll/minima

Build the blog

$ bundle exec jekyll serve
<snip>
Run in verbose mode to see all warnings.
                  done in 2.788 seconds.
Auto-regeneration: enabled for '/home/andy/devel/my-jekyll-blog'
Server address: http://127.0.0.1:4000/

Live reload uses a different command and port

Run in verbose mode to see all warnings.
                    done in 4.7 seconds.
 Auto-regeneration: enabled for 'devel/my-jekyll-blog'
LiveReload address: http://127.0.0.1:35729
    Server address: http://127.0.0.1:4000/
  Server running... press ctrl-c to stop.

Jekyll also produces a lot of warnings (deprecation) that clutter up the display. This is surprising (and irritating) for the latest version of Jekyll and the standard, bundled theme.

There is a '--quiet' option for 'jekyll build' but this doesn't appear to silence the warnings.

Attempting to access the live development server on port 35729 fails. However, the live reload is actually available on port 4000.

This port only serves livereload.js over HTTP.

Given Jekyll was first released back in 2008, Jekyll feels rather neglected and outdated to me. Tags didn't work properly. All tags were processed and listed but the click through from an individual article as '404 - Not Found' error.

Also Jekyll insists on blog posts following a naming convention ('yyyy-mm-dd-title.md').

Theme Time (secs) Notes
Default 5.091 Full
Default 1.029 Incremental
Default 8.561 Live reload

Useful SSG performance resources

Zach Leatherman (Eleventy lead developer) performed some performance benchmarks (in 2022) which are a useful benchmark comparing SSG's for pure Markdown conversion throughput for large sites.

However, Zach's tests don't include meta-data (tags, categories, dates) so aren't necessarily representative of a real-life blog or site.

https://www.zachleat.com/web/build-benchmark/

Generating representative test data is difficult but this Bash script scrapes a random Wikipedia page and generates Markdown (including tags and categories).

https://gist.github.com/jgreely/2338c72c825d2a93713e4f0fc0025985

Each SSG has its own format for front-matter. There are even two different formats for front matter; TOML and YAML.

Hugo has a very useful builtin conversion function to convert the Hugo front matter an all posts between the formats (including JSON).

$ hugo convert --help
Usage:
  hugo convert [command]

Available Commands:
  toJSON      Convert front matter to JSON
  toTOML      Convert front matter to TOML
  toYAML      Convert front matter to YAML

Commonmark_test

This is the famous ‘Hello world’ program written in Python in colour using Markdown.

#!/usr/bin/env python
import sys

def hello(name='world'):
    greeting = "hello " + name
    print(greeting)

if __name__ == "__main__":
    hello(*sys.argv[1:])

This took me a long time to get working.

The music video for Rihanna’s song American Oxygen depicts various moments from American history, including the inauguration of Barack Obama.

Why, sometimes I’ve believed as many as six impossible things before breakfast.

Everyone must attend the meeting at 5 o’clock today.

I am totally awesome.*

* for certain very small values of awesome

I have eaten\ the plums\ that were in\ the icebox

Chapter 1

Something about the room made him uneasy.

Chapter 2

It's behind you! Hurry before it

After the Big Bang

A brief summary of time

Life on earth

10 billion years

You reading this

13.7 billion years

The quote

Somewhere, something incredible is waiting to be known

has been ascribed to Carl Sagan.

My favorite Miss Manners quotes:

Allowing an unimportant mistake to pass without comment is a wonderful social grace.

Ideological differences are no excuse for rudeness.

  • Flour
  • Cheese
  • Tomatoes

Four steps to better sleep: 1. Stick to a sleep schedule 2. Create a bedtime ritual 3. Get comfortable 4. Manage stress

1986. What a great season. Arguably the finest season in the history of the franchise.

You can do anything at https://html5zombo.com

The University of Rwanda was formed in 2013 through the merger of Rwanda’s seven public institutions of higher education.

Hurricane Erika was the strongest and longest-lasting tropical cyclone in the 1997 Atlantic hurricane season.

Logo

When x = 3, that means x + 2 = 5

Who ate the most donuts this week?

Jeff  15
Sam   11
Robin  6
  • Fruit
  • Apple
  • Orange
  • Banana
  • Dairy
  • Milk
  • Cheese

  • World Cup 2014

  • Germany
  • Argentina
  • Netherlands
  • Rugby World Cup 2015
  • New Zealand
  • Australia
  • South Africa

  • Ingredients

    • spaghetti
    • marinara sauce
    • salt
  • Cooking

Bring water to boil, add a pinch of salt and spaghetti. Cook until pasta is tender.

  1. Serve

Drain the pasta on a plate. Add heated sauce.

No man is lonely eating spaghetti; it requires so much attention.

Bon appetit!

Column Left Column Right Column Centre
row1 1 1 1
row2 2 2 2
row3 3 3 3

Oracle SQLcl configuration

I use SQLcl a lot and install it on every environment I work on. Its fully compatible with SQL*Plus and has useful extensions to interact with OCI, Autonomous Databases and Data Pump.

My SQLcl configuration file is named 'login.sql' and located in the '~/work' directory. I also keep my 'tnsnames.ora' file here.

The location of these two Oracle configuration files is configured in '~/.bashrc'.

# Oracle TNS location
export TNS_ADMIN=$HOME/work

# SQLCL login file
export SQLPATH=$HOME/work

This is my SQLcl configuration file.

set editor emacs
set statusbar on
set statusbar add timing
set sqlformat ansiconsole
set highlighting on
set highlighting keyword foreground green
set highlighting identifier foreground magenta
set highlighting string foreground yellow
set highlighting number foreground cyan
set hig
comment background white
set highlighting comment foreground black

Sample output

SQL> select count(*) from dba_objects;

COUNT(*)
___________
358710

emacs ¦ 1:0 ¦ BILLY ¦ EDA_DEMO ¦ 00:00:00.953

what I use

I like reading about the hardware and software various people use so here's my version.

Introduction

I work for Oracle as a technical consultant based in the UK (fully remote). I'm old and evolved from a Unix/C developer to PL/SQL, Oracle DBA and now work on database migrations and Oracle Cloud Infrastructure (OCI).

Hardware

Lenovo ThinkCentre M900

  • Intel i7-6700
  • Memory 48GB (upgraded from 16GB)
  • Disk 1TB

Samsung Galaxy S24

Expensive phone kindly provided by my employer. I don't use many apps (Gmail, WhatsApp, BBC Sport, Tusky).

MacBook Pro

Expensive laptop kindly provided by my employer. I use it on the rare occasions I need to attend an office or customer site.

Huawei Android tablet

I don't have a personal laptop so I use this for idly wasting time.

Synology

Years ago, I acquired a FreeNAS unit after almost losing an essay (and my marriage) my wife had written for a Masters course. I subsequently replaced the FreeNAS with a Synology DS420+ which works fine (file backups, Jellyfin music server). The NAS has saved my bacon on more than one occasion and now I can't imagine being without it.

Software

Arch Linux

Former serial distro hopper. Now happy with Arch and Gnome desktop. Arch just works, has great documentation and provides a brilliant development environment (comprehensive range of latest packages).

GNU Emacs

I have used GNU Emacs for many years but am still learning about its power daily. I try to use core packages and keep my configuration minimal although I build the latest bleeding edge version (30.x).

  • Theme - Used 'monokai' for ages and now adopted Prot's excellent 'modus-vivendi-tinted'.
  • Orgmode
  • Org Roam
  • Vertico, Consult, Maginalia, Orderless
  • Magit
  • Jinx (spell checker)
  • Dashboard
  • Undo Tree
  • Pass

Thunderbird

My employer uses Outlook but we can run any email client so I run a local Dovecot IMAP server and Thunderbird.

I use Thunderbird to automatically fetch messages from Outlook and filters in a vain attempt to try to reduce the size of INBOX.

VirtualBox

I use VirtualBox a lot for demo environments, testing new Oracle features and experimenting.

I've also used Docker/Podman but struggle to fully embrace it as I prefer full control (and don't really understand Docker compose files).

Corporate

Standard list of tedious corporate applications I have to use. Most of these work on Arch.

  • Zoom
  • Teams
  • Slack
  • Confluence
  • Jira
  • VS-Code/SQL Developer (Oracle database client).

remapping multiple tablespaces in Data Pump

Occasionally I find myself migrating Oracle databases between environments using Data Pump.

Enterprise applications tend to use multiple tablespaces for logical separation (and historical reasons). However, this isn't possible when the target database is Autonomous Database (ADB) hosted on Oracle Cloud Infrastructure (OCI).

ADB is a managed service so DBA's can't create tablespaces and are limited to 'DATA'.

However, Oracle 19c Data Pump supports wildcards for the REMAP_TABLESPACE parameter which allows multiple tablespaces from the existing application to be mapped to the ADB DATA tablespace.

#!/bin/bash

for SCHEMA in MYSCHEMA
do
  PARFILE=/tmp/dpexp_$$.par

  cat > ${PARFILE} <<EOF
schemas=${SCHEMA}
logfile=imp_schema_${SCHEMA}.log
directory=TEST_DIR
dumpfile=exp_schema_${SCHEMA}.dmp
transform=disable_archive_logging:Y
table_exists_action=REPLACE
remap_tablespace=%:DATA
metrics=Y
logtime=ALL
EOF

  cat ${PARFILE}
  impdp user/pass@DB parfile=${PARFILE}
done

More info - Oracle 19C Data Pump documentation

blog questions challenge

I was interested by Kev Quirks Blog Questions Challenge, so heres my answers.

To recap, the questions are:

  1. Why did you start blogging in the first place ?
  2. What platform are you using to manage your blog and why did you choose it ?
  3. Have you blogged on other platforms before ?
  4. How do you write your posts? For example, in a local editing tool, or in a panel/dashboard that's part of your blog ?
  5. When do you feel most inspired to write ?
  6. Do you publish immediately after writing, or do you let it simmer a bit as a draft ?
  7. What's your favourite post on your blog ?
  8. Any future plans for your blog ? Maybe a redesign, a move to another platform, or adding a new feature ?

Why did you start blogging in the first place ?

I had a web site from 1999 but this was essentially a set of static HTML pages.

I'm an Oracle DBA/developer and there was an active Oracle blogging community who first piqued my interest in back in 2005. I am a serial experimenter and curious about new technologies so initially I chose Blogger and subsequently switched to Wordpress.

What platform are you using to manage your blog and why did you choose it ?

This blog currently uses Emacs, Hugo, GitHub and Netlify as I wanted to use as many moving parts as possible. This stack is also essentially a 'free' solution.

Have you blogged on other platforms before ?

Err, yes. I've used many blogging platforms (Blogger, Wordpress, Joomla, Drupal, Tumblr, Posterous, Serendipity, Jekyll, Pelican, Octopress, Habari, Nikola, Eleventy, write.as, Hugo).

How do you write your posts ?

Now I write in Emacs and orgmode. This was a recent, conscious decision as I wanted to standardise on orgmode markup. Trying to remember the subtle differences between Markdown and orgmode formats was irritating.

When do you feel most inspired to write ?

Unfortunately not very often.

Years ago, I tended to be prompted to post by other bloggers but, with the advent of the immediacy of social media, sadly the blogging community and the number of feeds in my RSS client has shrunk considerably.

Plus I'm lazy. Incredibly lazy.

Do you publish immediately or have Draft posts ?

Normally, I publish immediately. I really don't like content sitting in 'Drafts' which is akin to a dripping water tap, taunting me, nagging me.

However, I am slightly pedantic about presentation and typos, in particular, so will always preview the post locally in Hugo before publishing.

What's your favourite post on your blog ?

Easy. Two. Both involve hamsters.

Any future plans for your blog ?

Possibly. I'm quite happy with my existing setup but sometimes I think self hosting using WriteFreely would be easier and offer better integration with the Fediverse.

improving the FWP APEX application

Stung by the criticism of our Football Web Pages APEX application, we decide to try to address the various issues raised by end users and peer code review.

  1. When clicking ‘Fixtures’, I get ‘ORA-20999: REST Data Source returned an HTTP error: HTTP 400: Bad request’
  2. If you enter a Competition only, it works fine. If you enter a Team only, it works fine. If you enter both a ‘Competition’ and ‘Team’, the results look weird. Should ‘Team’ be a cascading LOV based on the ‘Competition’ ?
  3. The column names and labels need tidying up. There are a lot of meaningless ID fields displayed.
  4. It would be nice to have the option to review past results separately from fixtures in the future.
  5. Performance - the Popup LOV’s for Competition and Team are sluggish. Why are they so S L O W ?
  6. The navigation menu looks chaotic and ugly.

HTTP 400 error entering Fixtures report

This error is because the REST parameter for 'Competition' or 'Teams' is required. When we first run this page, there no values defined for the 'Competition' or 'Teams' parameters which results in the error.

A quick and easy solution is to simply default the competition to 'Premier League'.

Edit the 'Fixtures' page. This is Page 8 in my example. The page number may be different in your APEX environment.

FWP Fixtures FWP Fixtures

Edit the 'P8_COMPETITION' parameter.

Competition parameter Competition parameter

Filter on 'Default' and configure a default value with 'Type' set to 'Static' with the value set to '1' (Premier League).

Competition parameter default Competition parameter default

Save and test the changes. Now if you enter the 'Fixtures' page for the first time, you should see data displayed for the Premier League (instead of the HTTP 400 error).

Competition defaulted Competition defaulted

This may not necessarily be the best solution to this problem. For example, I would like the 'Competition' to default to 'Isthmian League - South Central' or the team to default to 'Kingstonian FC'. This requirement could be implemented using a user profile page.

Parameter validation

Defaulting the 'Competition' to Premier League may appear to have resolved the issue when neither of the 'Competition' and 'Team' parameters are supplied. However, you can easily reproduce the original issue by selecting the 'Select' value for each parameter and clicking 'Go'.

APEX provides a declarative solution for parameter validation which we can use to resolve this issue.

Navigate to the 'Fixtures' page in App Builder.

Fixtures validation Fixtures validation

Click the 'Processing' tab.

Create a Validation called 'ValidateParams'.

Click on 'Validating', then right-click and select 'Create Validation'. Scroll down to the 'Validation' section with Type = 'Expression' and Language = 'PL/SQL'.

Create fixtures validation Fixtures validation create

I always forget the semantics of the validation expression so I normally click the 'Help' tab in the middle pane for a quick reminder.

To pass the validation, and not raise an error message, when the employee is in department 30 or is a manager:

( :P2_DEPTNO = 30 or :P2_JOB = 'MANAGER' )

In our case, the two parameters are an exclusive OR. The user must either select a Competition or a Team but not both.

Therefore, our validation expression (which specifies when the parameters are valid) is:

(:P4_TEAM is null and :P4_COMPETITION is not null)
or
(:P4_TEAM is not null and :P4_COMPETITION is null)

APEX insists you enter a meaningful error message to the displayed to the end user if the validation fails.

You must select a competition or team.

Test the changes and check the user now gets an error message displayed.

Fixtures validation message Fixtures validation message

A lot of the FWP API's require this identical combination of parameters. Instead of copying and pasting this PL/SQL block, put it into a stored procedure, so you can reuse this logic. Then, if this logic subsequently changes in the future, you only have to change the code in one place.

Summary

We have (finally) addressed a couple of issues originally raised in October 2022.

This is the antithesis of the Agile development methodology but we will endeavour to address the remaining feedback during the course of 2025.