Skip to content

Commit 676d5a5

Browse files
committed
chore: pin PostgreSQL parser oracle sources
1 parent 91dab09 commit 676d5a5

4 files changed

Lines changed: 429 additions & 0 deletions

File tree

scripts/pg_compat/common.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import hashlib
2+
import json
3+
import os
4+
import re
5+
import tempfile
6+
from pathlib import Path
7+
8+
9+
REQUIRED_ROLES = ("previous", "target")
10+
REQUIRED_VERSION_FIELDS = (
11+
"branch",
12+
"commit",
13+
"pg_version",
14+
"pg_version_num",
15+
"postgres_sha256",
16+
)
17+
18+
19+
def load_pins(path):
20+
path = Path(path)
21+
with path.open(encoding="utf-8") as pins_file:
22+
pins = json.load(pins_file)
23+
24+
if not isinstance(pins, dict) or "libpg_query_url" not in pins:
25+
raise ValueError("missing required pin: libpg_query_url")
26+
27+
versions = pins.get("versions")
28+
if not isinstance(versions, dict):
29+
raise ValueError("missing required pin: versions")
30+
31+
for role in REQUIRED_ROLES:
32+
version = versions.get(role)
33+
if not isinstance(version, dict):
34+
raise ValueError(f"missing required pin: versions.{role}")
35+
for field in REQUIRED_VERSION_FIELDS:
36+
if field not in version:
37+
raise ValueError(f"missing required pin: versions.{role}.{field}")
38+
39+
return pins
40+
41+
42+
def parse_makefile_pg_version(text):
43+
version_match = re.search(r"^PG_VERSION\s*=\s*(\S+)\s*$", text, re.MULTILINE)
44+
version_num_match = re.search(r"^PG_VERSION_NUM\s*=\s*(\d+)\s*$", text, re.MULTILINE)
45+
46+
if version_match is None:
47+
raise ValueError("PG_VERSION is absent from Makefile")
48+
if version_num_match is None:
49+
raise ValueError("PG_VERSION_NUM is absent from Makefile")
50+
51+
return version_match.group(1), int(version_num_match.group(1))
52+
53+
54+
def statement_id(normalized_sql, oracle_node):
55+
digest_input = f"{oracle_node}\0{normalized_sql}".encode("utf-8")
56+
return hashlib.sha256(digest_input).hexdigest()[:24]
57+
58+
59+
def read_jsonl(path):
60+
path = Path(path)
61+
with path.open(encoding="utf-8") as jsonl_file:
62+
for line_number, line in enumerate(jsonl_file, start=1):
63+
if not line.strip():
64+
continue
65+
try:
66+
yield json.loads(line)
67+
except json.JSONDecodeError as error:
68+
raise ValueError(
69+
f"{path}:{line_number}: invalid JSON: {error.msg}"
70+
) from error
71+
72+
73+
def atomic_write_text(path, text):
74+
path = Path(path)
75+
path.parent.mkdir(parents=True, exist_ok=True)
76+
descriptor, temporary_path = tempfile.mkstemp(
77+
dir=path.parent,
78+
prefix=f".{path.name}.",
79+
suffix=".tmp",
80+
text=True,
81+
)
82+
83+
try:
84+
with os.fdopen(descriptor, "w", encoding="utf-8") as temporary_file:
85+
temporary_file.write(text)
86+
os.replace(temporary_path, path)
87+
except BaseException:
88+
try:
89+
os.unlink(temporary_path)
90+
except FileNotFoundError:
91+
pass
92+
raise
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
5+
PINS="${PG_COMPAT_PINS:-${ROOT}/tests/pg_compat/upstream_pins.json}"
6+
CACHE="${PG_COMPAT_CACHE:-/tmp/parsersql-pg-compat}"
7+
WITH_POSTGRES_SOURCE=0
8+
9+
usage() {
10+
echo "Usage: $0 [--with-postgres-source]" >&2
11+
}
12+
13+
if [[ $# -gt 1 ]]; then
14+
usage
15+
exit 2
16+
fi
17+
if [[ $# -eq 1 ]]; then
18+
if [[ "$1" != "--with-postgres-source" ]]; then
19+
usage
20+
exit 2
21+
fi
22+
WITH_POSTGRES_SOURCE=1
23+
fi
24+
25+
cd "$ROOT"
26+
27+
LIBPG_QUERY_URL="$(
28+
python3 - "$PINS" <<'PY'
29+
import sys
30+
31+
from scripts.pg_compat.common import load_pins
32+
33+
print(load_pins(sys.argv[1])["libpg_query_url"])
34+
PY
35+
)"
36+
37+
pin_values() {
38+
local role="$1"
39+
python3 - "$PINS" "$role" <<'PY'
40+
import sys
41+
42+
from scripts.pg_compat.common import load_pins
43+
44+
version = load_pins(sys.argv[1])["versions"][sys.argv[2]]
45+
print(
46+
version["branch"],
47+
version["commit"],
48+
version["pg_version"],
49+
version["pg_version_num"],
50+
version["postgres_sha256"],
51+
sep="\t",
52+
)
53+
PY
54+
}
55+
56+
verify_makefile_version() {
57+
local checkout="$1"
58+
local expected_version="$2"
59+
local expected_version_num="$3"
60+
local actual_version
61+
local actual_version_num
62+
63+
IFS=$'\t' read -r actual_version actual_version_num <<< "$(
64+
python3 - "$checkout/Makefile" <<'PY'
65+
import sys
66+
from pathlib import Path
67+
68+
from scripts.pg_compat.common import parse_makefile_pg_version
69+
70+
version, version_num = parse_makefile_pg_version(
71+
Path(sys.argv[1]).read_text(encoding="utf-8")
72+
)
73+
print(version, version_num, sep="\t")
74+
PY
75+
)"
76+
77+
if [[ "$actual_version" != "$expected_version" ]]; then
78+
echo "PG_VERSION mismatch in ${checkout}: expected ${expected_version}, got ${actual_version}" >&2
79+
exit 1
80+
fi
81+
if [[ "$actual_version_num" != "$expected_version_num" ]]; then
82+
echo "PG_VERSION_NUM mismatch in ${checkout}: expected ${expected_version_num}, got ${actual_version_num}" >&2
83+
exit 1
84+
fi
85+
}
86+
87+
fetch_libpg_query() {
88+
local role="$1"
89+
local branch="$2"
90+
local commit="$3"
91+
local pg_version="$4"
92+
local pg_version_num="$5"
93+
local checkout="${CACHE}/libpg_query/${role}"
94+
local actual_head
95+
96+
mkdir -p "$(dirname "$checkout")"
97+
if [[ ! -d "$checkout/.git" ]]; then
98+
if [[ -e "$checkout" ]]; then
99+
echo "Cache path exists but is not a Git checkout: ${checkout}" >&2
100+
exit 1
101+
fi
102+
git clone --no-checkout "$LIBPG_QUERY_URL" "$checkout"
103+
fi
104+
105+
git -C "$checkout" remote set-url origin "$LIBPG_QUERY_URL"
106+
echo "Fetching libpg_query ${role}: ${branch} at ${commit}"
107+
git -C "$checkout" fetch --force --no-tags origin "$commit"
108+
git -C "$checkout" checkout --detach --force "$commit"
109+
110+
actual_head="$(git -C "$checkout" rev-parse HEAD)"
111+
if [[ "$actual_head" != "$commit" ]]; then
112+
echo "HEAD mismatch in ${checkout}: expected ${commit}, got ${actual_head}" >&2
113+
exit 1
114+
fi
115+
116+
verify_makefile_version "$checkout" "$pg_version" "$pg_version_num"
117+
}
118+
119+
sha256_file() {
120+
python3 - "$1" <<'PY'
121+
import hashlib
122+
import sys
123+
from pathlib import Path
124+
125+
digest = hashlib.sha256()
126+
with Path(sys.argv[1]).open("rb") as source:
127+
for chunk in iter(lambda: source.read(1024 * 1024), b""):
128+
digest.update(chunk)
129+
print(digest.hexdigest())
130+
PY
131+
}
132+
133+
fetch_postgres_source() {
134+
local pg_version="$1"
135+
local expected_sha256="$2"
136+
local postgres_root="${CACHE}/postgresql"
137+
local archive="${postgres_root}/postgresql-${pg_version}.tar.bz2"
138+
local source_dir="${postgres_root}/postgresql-${pg_version}"
139+
local archive_url="https://ftp.postgresql.org/pub/source/v${pg_version}/postgresql-${pg_version}.tar.bz2"
140+
local download_tmp
141+
local extract_tmp
142+
local actual_sha256
143+
144+
mkdir -p "$postgres_root"
145+
if [[ ! -f "$archive" ]]; then
146+
download_tmp="$(mktemp "${postgres_root}/.postgresql-${pg_version}.download.XXXXXX")"
147+
if ! curl --fail --location --retry 3 --output "$download_tmp" "$archive_url"; then
148+
rm -f "$download_tmp"
149+
return 1
150+
fi
151+
mv "$download_tmp" "$archive"
152+
fi
153+
154+
actual_sha256="$(sha256_file "$archive")"
155+
if [[ "$actual_sha256" != "$expected_sha256" ]]; then
156+
echo "SHA-256 mismatch for ${archive}: expected ${expected_sha256}, got ${actual_sha256}" >&2
157+
exit 1
158+
fi
159+
160+
if [[ ! -d "$source_dir" ]]; then
161+
extract_tmp="$(mktemp -d "${postgres_root}/.postgresql-${pg_version}.extract.XXXXXX")"
162+
if ! tar -xjf "$archive" -C "$extract_tmp"; then
163+
rm -rf "$extract_tmp"
164+
return 1
165+
fi
166+
mv "${extract_tmp}/postgresql-${pg_version}" "$source_dir"
167+
rmdir "$extract_tmp"
168+
fi
169+
}
170+
171+
for role in previous target; do
172+
IFS=$'\t' read -r branch commit pg_version pg_version_num postgres_sha256 <<< "$(pin_values "$role")"
173+
fetch_libpg_query "$role" "$branch" "$commit" "$pg_version" "$pg_version_num"
174+
if [[ "$WITH_POSTGRES_SOURCE" -eq 1 ]]; then
175+
fetch_postgres_source "$pg_version" "$postgres_sha256"
176+
fi
177+
done

0 commit comments

Comments
 (0)