Skip to content

Commit e40bc7b

Browse files
committed
Add GraalPy Oracle Database connection demo
1 parent 84e3e2e commit e40bc7b

6 files changed

Lines changed: 178 additions & 0 deletions

File tree

graalpy/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ This directory contains demo applications and guides for [GraalPy](https://www.g
99
- [Minimal Java application that embeds GraalPy](graalpy-starter/)
1010
- [Minimal Java application that embeds `openai` Python package with GraalPy](graalpy-openai-starter/)
1111
- [Embed `qrcode` Python package with GraalPy in JBang](graalpy-jbang-qrcode/)
12+
- [Connect to local Oracle Database Free with GraalPy and `python-oracledb`](oracle-graalpy-local/)
1213
- [Embed SVG charting library `pygal` with GraalPy in Micronaut](graalpy-micronaut-pygal-charts/)
1314
- [Embed SVG charting library `pygal` with GraalPy in Spring Boot](graalpy-spring-boot-pygal-charts/)
1415

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__pycache__/
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
# Oracle Database Local Connection (GraalPy + python-oracledb) Native Demo
2+
3+
This demo shows a small [Flask](https://flask.palletsprojects.com/) application running on **GraalPy** and connecting to a local [Oracle Database Free](https://www.oracle.com/database/free/get-started/) instance using the **python-oracledb** driver.
4+
5+
> The [python-oracledb driver](https://oracle.github.io/python-oracledb/) is the open-source Python module allowing Python programs to connect directly to Oracle Database with no extra libraries needed.
6+
7+
This project provides a local baseline application for **GraalPy** that can also be compiled into a native standalone executable.
8+
The application exposes one `GET` HTTP endpoint, runs `select 'Hello from Oracle' from dual`, and returns the result as JSON.
9+
10+
## Prerequisites
11+
12+
* [GraalPy 25.0.2](https://www.graalvm.org/python/python-developers/docs/#installation)
13+
* [GraalVM 25.0.2](https://www.graalvm.org/downloads/)
14+
* Docker installed and running
15+
16+
## Start Oracle Database Free
17+
18+
1. Log in to Oracle Container Registry:
19+
```bash
20+
docker login container-registry.oracle.com
21+
```
22+
23+
> If you do not want to log in to Oracle Container Registry, you can use the community-maintained Docker Hub image [gvenzl/oracle-free](https://hub.docker.com/r/gvenzl/oracle-free) instead.
24+
25+
2. Pull the Oracle Database Free image:
26+
```bash
27+
docker pull container-registry.oracle.com/database/free:latest
28+
```
29+
30+
3. Start the database:
31+
```bash
32+
docker run -d \
33+
--name oracle-free \
34+
-p 1521:1521 \
35+
-e ORACLE_PWD=oraclepwd \
36+
container-registry.oracle.com/database/free:latest
37+
```
38+
39+
4. Wait for the database to become ready:
40+
```bash
41+
docker logs -f oracle-free
42+
```
43+
Wait until the logs show a readiness message such as `DATABASE IS READY TO USE!`, then press `Ctrl+C`.
44+
45+
5. Create the application user:
46+
```bash
47+
docker exec -it oracle-free sqlplus system/oraclepwd@FREEPDB1
48+
```
49+
50+
Then run:
51+
```sql
52+
CREATE USER appuser IDENTIFIED BY apppassword;
53+
GRANT CONNECT TO appuser;
54+
GRANT CREATE SESSION TO appuser;
55+
```
56+
Exit the SQL editor.
57+
58+
Default values for `ORACLE_USER`, `ORACLE_PASSWORD`, `ORACLE_DSN`, and `PORT` are already specified in the application, so no further configuration is necessary for this demo.
59+
60+
## Run from Source with GraalPy
61+
62+
1. Create a GraalPy virtual environment:
63+
```bash
64+
${GRAALPY:-graalpy} -m venv target/venv
65+
```
66+
67+
2. Install the Python dependencies:
68+
```bash
69+
target/venv/bin/graalpy -m pip install -r requirements.txt
70+
```
71+
72+
3. Start the application:
73+
```bash
74+
target/venv/bin/graalpy app.py
75+
```
76+
77+
4. Test the endpoint from another terminal:
78+
```bash
79+
curl http://localhost:8080/
80+
```
81+
82+
You should see this response:
83+
```json
84+
{"message":"Hello from Oracle"}
85+
```
86+
87+
## Build a Native Standalone Executable
88+
89+
90+
For building a Python standalone application, native executable, set `JAVA_HOME` and `PATH` to the required GraalVM version:
91+
```bash
92+
export JAVA_HOME="$HOME/.sdkman/candidates/java/<version>-graal"
93+
export PATH="$JAVA_HOME/bin:$PATH"
94+
```
95+
96+
The GraalPy command to build a standalone executable is:
97+
```bash
98+
graalpy -m standalone native \
99+
--module app.py \
100+
--output target/standalone-app \
101+
--venv target/venv
102+
```
103+
104+
For convenience, the script `build-native.sh` is provided for you: it creates a virtual environment in `target/venv`, installs Flask and `python-oracledb` libraries, and builds a native standalone executable.
105+
106+
1. Run it:
107+
```bash
108+
./build-native.sh
109+
```
110+
Building a native executable takes a few minutes.
111+
The file is created at `target/standalone-app`.
112+
113+
2. Start this native application:
114+
```bash
115+
./target/standalone-app
116+
```
117+
118+
3. Test it the same way as before:
119+
```bash
120+
curl http://localhost:8080/
121+
```
122+
123+
## Summary
124+
125+
This demo showcases a Flask application packaged as a GraalPy native executable, connecting to Oracle Database using the `python-oracledb` driver.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Copyright (c) 2025-2026, Oracle and/or its affiliates. All rights reserved.
2+
import os
3+
4+
from flask import Flask, jsonify
5+
import oracledb
6+
7+
app = Flask(__name__)
8+
9+
ORACLE_USER = os.getenv("ORACLE_USER", "appuser")
10+
ORACLE_PASSWORD = os.getenv("ORACLE_PASSWORD", "apppassword")
11+
ORACLE_DSN = os.getenv("ORACLE_DSN", "localhost:1521/freepdb1")
12+
PORT = int(os.getenv("PORT", "8080"))
13+
14+
15+
@app.route("/")
16+
def db_example():
17+
try:
18+
with oracledb.connect(
19+
user=ORACLE_USER,
20+
password=ORACLE_PASSWORD,
21+
dsn=ORACLE_DSN,
22+
) as conn:
23+
with conn.cursor() as cur:
24+
cur.execute("select 'Hello from Oracle' as msg from dual")
25+
row = cur.fetchone()
26+
return jsonify({"message": row[0] if row else None})
27+
except Exception as exc:
28+
return jsonify({"error": str(exc)}), 500
29+
30+
31+
if __name__ == "__main__":
32+
app.run(host="0.0.0.0", port=PORT, use_reloader=False)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#!/usr/bin/env bash
2+
3+
set -euo pipefail
4+
5+
GRAALPY="${GRAALPY:-graalpy}"
6+
VENV_DIR="${VENV_DIR:-target/venv}"
7+
OUTPUT="${OUTPUT:-target/standalone-app}"
8+
9+
mkdir -p "$(dirname "${OUTPUT}")"
10+
11+
"${GRAALPY}" -m venv "${VENV_DIR}"
12+
"${VENV_DIR}/bin/graalpy" -m pip install -r requirements.txt
13+
14+
"${GRAALPY}" -m standalone native \
15+
--module app.py \
16+
--output "${OUTPUT}" \
17+
--venv "${VENV_DIR}"
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Flask==3.1.0
2+
oracledb==3.4.2

0 commit comments

Comments
 (0)