Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export type GeneratedMobileExtensionProof = {
readonly selectedExtensionDependencies: readonly string[];
};

export const GENERATED_MOBILE_EXTENSION_METADATA_SHA256 = "26ce911f641272aa18249e7c7d044dfa5ea7061d07119bb275544e164bb9249a" as const;
export const GENERATED_MOBILE_EXTENSION_METADATA_SHA256 = "dbe1ab284693ef923cb12e35e1c75bcc7fc1ed42af1fecf9fe9fee0aaf0ef8d0" as const;

export const GENERATED_MOBILE_EXTENSION_PLAN = [
{
Expand Down Expand Up @@ -165,7 +165,9 @@ export const GENERATED_MOBILE_EXTENSION_PLAN = [
{
"sqlName": "postgis",
"createsExtension": true,
"selectedExtensionDependencies": []
"selectedExtensionDependencies": [
"fuzzystrmatch"
]
},
{
"sqlName": "seg",
Expand Down Expand Up @@ -353,11 +355,15 @@ export const GENERATED_MOBILE_EXTENSION_SMOKE = {
],
"postgis": [
"CREATE EXTENSION IF NOT EXISTS postgis_raster;",
"CREATE EXTENSION IF NOT EXISTS postgis_topology;",
"CREATE EXTENSION IF NOT EXISTS fuzzystrmatch;",
"CREATE EXTENSION IF NOT EXISTS postgis_tiger_geocoder;",
"DO $$ BEGIN\n IF EXISTS (SELECT 1 FROM topology.topology WHERE name = 'oliphaunt_postgis_topology') THEN\n PERFORM topology.DropTopology('oliphaunt_postgis_topology');\n END IF;\n PERFORM topology.CreateTopology('oliphaunt_postgis_topology', 4326);\n PERFORM topology.ST_AddIsoNode('oliphaunt_postgis_topology', NULL, ST_SetSRID(ST_MakePoint(1, 1), 4326));\nEND $$;",
"DROP TABLE IF EXISTS oliphaunt_postgis_points;",
"CREATE TABLE oliphaunt_postgis_points(id int PRIMARY KEY, geom geometry(Point, 4326));",
"INSERT INTO oliphaunt_postgis_points VALUES\n (1, ST_SetSRID(ST_MakePoint(-71.060316, 48.432044), 4326)),\n (2, ST_SetSRID(ST_MakePoint(-71.061, 48.433), 4326));",
"CREATE INDEX oliphaunt_postgis_points_gix ON oliphaunt_postgis_points USING GIST (geom);",
"-- oliphaunt-verify\nDO $$\nDECLARE\n distance float8;\n srid int;\n area float8;\n polygons int;\n nearby int;\n gdal_drivers int;\n raster_roundtrip raster;\n raster_value float8;\nBEGIN\n SET LOCAL postgis.gdal_enabled_drivers = 'GTiff';\n SELECT ST_Distance(ST_GeomFromText('POINT(0 0)'), ST_GeomFromText('POINT(3 4)')) INTO distance;\n IF distance <> 5 THEN\n RAISE EXCEPTION 'postgis geometry distance failed: %', distance;\n END IF;\n IF ST_AsText(ST_Buffer(ST_GeomFromText('POINT(0 0)'), 1, 'quad_segs=1')) IS NULL THEN\n RAISE EXCEPTION 'postgis buffer failed';\n END IF;\n IF NOT ST_Within(\n ST_GeomFromText('POINT(0.5 0.5)'),\n ST_GeomFromText('POLYGON((0 0,0 1,1 1,1 0,0 0))')\n ) THEN\n RAISE EXCEPTION 'postgis within failed';\n END IF;\n SELECT ST_SRID(ST_Transform(ST_SetSRID(ST_MakePoint(-71.060316, 48.432044), 4326), 3857)) INTO srid;\n IF srid <> 3857 THEN\n RAISE EXCEPTION 'postgis transform failed: %', srid;\n END IF;\n SELECT ST_Area(ST_Transform(ST_SetSRID(ST_MakePolygon(ST_GeomFromText('LINESTRING(-71.1776848522251 42.3902896512902,-71.1776843766797 42.3903701743239,-71.1775844305465 42.3903829478009,-71.1775825927231 42.3902893647987,-71.1776848522251 42.3902896512902)')), 4326), 26986)) INTO area;\n IF area <= 0 THEN\n RAISE EXCEPTION 'postgis projected area failed: %', area;\n END IF;\n SELECT ST_NumGeometries(ST_Polygonize(ARRAY[\n ST_GeomFromText('LINESTRING(0 0, 1 0)'),\n ST_GeomFromText('LINESTRING(1 0, 1 1)'),\n ST_GeomFromText('LINESTRING(1 1, 0 1)'),\n ST_GeomFromText('LINESTRING(0 1, 0 0)')\n ])) INTO polygons;\n IF polygons <> 1 THEN\n RAISE EXCEPTION 'postgis polygonize failed: %', polygons;\n END IF;\n SELECT count(*) INTO nearby\n FROM oliphaunt_postgis_points\n WHERE ST_DWithin(\n geom::geography,\n ST_SetSRID(ST_MakePoint(-71.060316, 48.432044), 4326)::geography,\n 200\n );\n IF nearby <> 2 THEN\n RAISE EXCEPTION 'postgis dwithin failed: %', nearby;\n END IF;\n SELECT count(*) INTO gdal_drivers\n FROM ST_GDALDrivers()\n WHERE short_name = 'GTiff' AND can_read AND can_write;\n IF gdal_drivers <> 1 THEN\n RAISE EXCEPTION 'postgis raster GeoTIFF driver is unavailable';\n END IF;\n SELECT ST_FromGDALRaster(\n ST_AsGDALRaster(\n ST_AddBand(\n ST_MakeEmptyRaster(2, 2, 0, 0, 1, -1, 0, 0, 4326),\n '8BUI'::text,\n 7::double precision,\n 0::double precision\n ),\n 'GTiff'\n )\n ) INTO raster_roundtrip;\n SELECT ST_Value(raster_roundtrip, 1, 1, 1) INTO raster_value;\n IF raster_value IS DISTINCT FROM 7 OR ST_SRID(raster_roundtrip) IS DISTINCT FROM 4326\n OR ST_Width(raster_roundtrip) IS DISTINCT FROM 2 OR ST_Height(raster_roundtrip) IS DISTINCT FROM 2 THEN\n RAISE EXCEPTION 'postgis raster GDAL round-trip failed: value %, srid %',\n raster_value,\n ST_SRID(raster_roundtrip);\n END IF;\nEND $$;"
"-- oliphaunt-verify\nDO $$\nDECLARE\n distance float8;\n srid int;\n area float8;\n polygons int;\n nearby int;\n gdal_drivers int;\n raster_roundtrip raster;\n raster_value float8;\n topology_nodes int;\n normalized tiger.norm_addy;\nBEGIN\n SELECT count(*) INTO topology_nodes FROM oliphaunt_postgis_topology.node\n WHERE ST_Equals(geom, ST_SetSRID(ST_MakePoint(1, 1), 4326));\n IF topology_nodes <> 1 OR EXISTS (SELECT 1 FROM topology.ValidateTopology('oliphaunt_postgis_topology')) THEN\n RAISE EXCEPTION 'postgis topology persistence or validation failed: % nodes', topology_nodes;\n END IF;\n normalized := tiger.normalize_address('1 Devonshire Place, Boston, MA 02109');\n IF normalized.address IS DISTINCT FROM 1 OR normalized.streetname IS DISTINCT FROM 'Devonshire'\n OR normalized.streettypeabbrev IS DISTINCT FROM 'Pl' OR normalized.location IS DISTINCT FROM 'Boston'\n OR normalized.stateabbrev IS DISTINCT FROM 'MA' OR normalized.zip IS DISTINCT FROM '02109'\n OR normalized.parsed IS DISTINCT FROM true THEN\n RAISE EXCEPTION 'postgis tiger address normalization failed: %', normalized;\n END IF;\n SET LOCAL postgis.gdal_enabled_drivers = 'GTiff';\n SELECT ST_Distance(ST_GeomFromText('POINT(0 0)'), ST_GeomFromText('POINT(3 4)')) INTO distance;\n IF distance <> 5 THEN\n RAISE EXCEPTION 'postgis geometry distance failed: %', distance;\n END IF;\n IF ST_AsText(ST_Buffer(ST_GeomFromText('POINT(0 0)'), 1, 'quad_segs=1')) IS NULL THEN\n RAISE EXCEPTION 'postgis buffer failed';\n END IF;\n IF NOT ST_Within(\n ST_GeomFromText('POINT(0.5 0.5)'),\n ST_GeomFromText('POLYGON((0 0,0 1,1 1,1 0,0 0))')\n ) THEN\n RAISE EXCEPTION 'postgis within failed';\n END IF;\n SELECT ST_SRID(ST_Transform(ST_SetSRID(ST_MakePoint(-71.060316, 48.432044), 4326), 3857)) INTO srid;\n IF srid <> 3857 THEN\n RAISE EXCEPTION 'postgis transform failed: %', srid;\n END IF;\n SELECT ST_Area(ST_Transform(ST_SetSRID(ST_MakePolygon(ST_GeomFromText('LINESTRING(-71.1776848522251 42.3902896512902,-71.1776843766797 42.3903701743239,-71.1775844305465 42.3903829478009,-71.1775825927231 42.3902893647987,-71.1776848522251 42.3902896512902)')), 4326), 26986)) INTO area;\n IF area <= 0 THEN\n RAISE EXCEPTION 'postgis projected area failed: %', area;\n END IF;\n SELECT ST_NumGeometries(ST_Polygonize(ARRAY[\n ST_GeomFromText('LINESTRING(0 0, 1 0)'),\n ST_GeomFromText('LINESTRING(1 0, 1 1)'),\n ST_GeomFromText('LINESTRING(1 1, 0 1)'),\n ST_GeomFromText('LINESTRING(0 1, 0 0)')\n ])) INTO polygons;\n IF polygons <> 1 THEN\n RAISE EXCEPTION 'postgis polygonize failed: %', polygons;\n END IF;\n SELECT count(*) INTO nearby\n FROM oliphaunt_postgis_points\n WHERE ST_DWithin(\n geom::geography,\n ST_SetSRID(ST_MakePoint(-71.060316, 48.432044), 4326)::geography,\n 200\n );\n IF nearby <> 2 THEN\n RAISE EXCEPTION 'postgis dwithin failed: %', nearby;\n END IF;\n SELECT count(*) INTO gdal_drivers\n FROM ST_GDALDrivers()\n WHERE short_name = 'GTiff' AND can_read AND can_write;\n IF gdal_drivers <> 1 THEN\n RAISE EXCEPTION 'postgis raster GeoTIFF driver is unavailable';\n END IF;\n SELECT ST_FromGDALRaster(\n ST_AsGDALRaster(\n ST_AddBand(\n ST_MakeEmptyRaster(2, 2, 0, 0, 1, -1, 0, 0, 4326),\n '8BUI'::text,\n 7::double precision,\n 0::double precision\n ),\n 'GTiff'\n )\n ) INTO raster_roundtrip;\n SELECT ST_Value(raster_roundtrip, 1, 1, 1) INTO raster_value;\n IF raster_value IS DISTINCT FROM 7 OR ST_SRID(raster_roundtrip) IS DISTINCT FROM 4326\n OR ST_Width(raster_roundtrip) IS DISTINCT FROM 2 OR ST_Height(raster_roundtrip) IS DISTINCT FROM 2 THEN\n RAISE EXCEPTION 'postgis raster GDAL round-trip failed: value %, srid %',\n raster_value,\n ST_SRID(raster_roundtrip);\n END IF;\nEND $$;"
],
"seg": [
"DO $$ BEGIN IF '7(+-)1'::seg::text <> '6 .. 8' THEN RAISE EXCEPTION 'seg cast failed'; END IF; END $$;"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ const metadata = {
sqlName: 'pgtap',
createsExtension: true,
nativeModuleStem: null,
sqlMembers: ['pgtap'],
nativeModuleStems: [],
dependencies: [],
dataFiles: [],
extensionSqlFileNames: ['uninstall_pgtap.sql'],
Expand Down Expand Up @@ -46,6 +48,8 @@ if (phase === 'prepare-binaries') {
sqlName: 'auto_explain',
createsExtension: false,
nativeModuleStem: 'auto_explain',
sqlMembers: [],
nativeModuleStems: ['auto_explain'],
extensionSqlFileNames: [],
extensionSqlFilePrefixes: [],
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
#!/usr/bin/env bun
import { fileURLToPath } from 'node:url';
import { promises as fs } from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { tarHeader } from '../../../../../tools/packaging/archive-directory.mts';
import { promises as fs } from 'node:fs';

import { validateWindowsExtensionArtifactBinaryContract } from './stage-windows-binary-contract.mts';
import { inspectPlatformBinaryTree } from '../../../../../tools/packaging/platform-binary-contract.mts';
import {
validateExtensionArtifactArchivePlan,
validateExtensionArtifactCompressedBytes,
} from '../../../tools/extension-artifact-archive-policy.mts';
import {
extensionControlDefaultVersion,
isCanonicalExtensionInstallSql,
validateExtensionInstallSqlReachability,
} from '../../packages/tools/extension-artifact-inventory.mts';
import { canonicalGzipSync } from '../../../../../tools/packaging/portable-archive.mts';
import {
assertReleaseNoticesInArchive,
stageReleaseNotices,
} from '../../../../../tools/packaging/release-notices.mts';
import { stageExtensionUpstreamLicenses } from '../../../tools/extension-upstream-licenses.mts';
import { canonicalGzipSync } from '../../../../../tools/packaging/portable-archive.mts';
import { extensionSqlNames } from '../../../../../tools/release/release-artifact-targets.mts';
import {
validateExtensionArtifactArchivePlan,
validateExtensionArtifactCompressedBytes,
} from '../../../tools/extension-artifact-archive-policy.mts';
import { stageExtensionUpstreamLicenses } from '../../../tools/extension-upstream-licenses.mts';
import {
loadNativeComponentContract,
resolveNativeComponentClosure,
} from '../../../tools/native-component-contract.mts';
import {
extensionControlDefaultVersion,
extensionNativeArtifactClosure,
isCanonicalExtensionInstallSql,
validateExtensionInstallSqlReachability,
} from '../../packages/tools/extension-artifact-inventory.mts';
import { validateWindowsExtensionArtifactBinaryContract } from './stage-windows-binary-contract.mts';

const scriptDir = path.dirname(fileURLToPath(import.meta.url));
const root = path.resolve(scriptDir, '../../../../..');
Expand Down Expand Up @@ -785,6 +785,12 @@ function artifactMobilePrebuilt(args) {

function extensionSqlFileBelongs(sqlName, fileName, extraSql, createsExtension) {
return (
extraSql.controls.includes(fileName) ||
extraSql.controls.some(
(control) =>
fileName.startsWith(`${control.slice(0, -'.control'.length)}--`) &&
fileName.endsWith('.sql'),
) ||
(createsExtension && fileName === `${sqlName}.control`) ||
(createsExtension && fileName === `${sqlName}.sql`) ||
(createsExtension && fileName.startsWith(`${sqlName}--`) && fileName.endsWith('.sql')) ||
Expand All @@ -793,7 +799,7 @@ function extensionSqlFileBelongs(sqlName, fileName, extraSql, createsExtension)
);
}

async function extensionSqlMetadata(sqlName) {
async function extensionSqlMetadata(sqlName, target) {
const prefixes = await extensionArtifactList(sqlName, 'extension_sql_file_prefixes');
const names = await extensionArtifactList(sqlName, 'extension_sql_file_names');
if (new Set(prefixes).size !== prefixes.length || new Set(names).size !== names.length) {
Expand All @@ -810,7 +816,10 @@ async function extensionSqlMetadata(sqlName) {
fail(`prebuilt extension '${sqlName}' SQL file prefix '${prefix}' must not contain '.'`);
}
}
return { names, prefixes };
const closure = extensionNativeArtifactClosure(sqlName, target);
// Mobile combines companion objects into its primary static module.
if (!DESKTOP_NATIVE_TARGETS.has(target)) closure.modules = [];
return { names, prefixes, ...closure };
}

async function ensureParent(file) {
Expand Down Expand Up @@ -898,6 +907,21 @@ async function copySqlFiles(args, artifactRoot, artifactFiles, extraSql) {
label: `prebuilt extension artifact ${artifactRoot}`,
});
}
for (const controlFile of extraSql.controls) {
if (controlFile === `${args.sqlName}.control`) continue;
const controlPath = path.join(targetDir, controlFile);
if (!copiedFileNames.includes(controlFile)) {
fail(
`prebuilt extension artifact ${artifactRoot} is missing companion control ${controlFile}`,
);
}
validateExtensionInstallSqlReachability({
sqlName: controlFile.slice(0, -'.control'.length),
control: await fs.readFile(controlPath, 'utf8'),
fileNames: copiedFileNames,
label: `prebuilt extension artifact ${artifactRoot}`,
});
}
if (!args.createsExtension && copied === 0) {
return;
}
Expand Down Expand Up @@ -969,25 +993,27 @@ function extensionMetadata(args, extraSql) {
};
}

async function writeArtifactDirectory(artifactRoot, args) {
export async function writeArtifactDirectory(artifactRoot, args) {
const filesRoot = path.join(artifactRoot, 'files');
const extraSql = await extensionSqlMetadata(args.sqlName);
const extraSql = await extensionSqlMetadata(args.sqlName, args.nativeTarget);
const metadata = extensionMetadata(args, extraSql);
const sqlMembers = sortedDeduped([
...(args.createsExtension ? [args.sqlName] : []),
...extraSql.controls.map((control) => control.slice(0, -'.control'.length)),
]);
await copySqlFiles(args, artifactRoot, filesRoot, extraSql);
for (const dataFile of metadata.dataFiles) {
await copyRuntimeRelativeFile(args.runtime, filesRoot, `share/postgresql/${dataFile}`);
}
if (metadata.nativeModuleFile.length > 0) {
await copyRuntimeRelativeFile(
args.runtime,
filesRoot,
`lib/postgresql/${metadata.nativeModuleFile}`,
);
const modules = new Set(extraSql.modules);
if (metadata.nativeModuleFile.length > 0) modules.add(metadata.nativeModuleFile);
for (const module of modules) {
await copyRuntimeRelativeFile(args.runtime, filesRoot, `lib/postgresql/${module}`);
if (DESKTOP_NATIVE_TARGETS.has(args.nativeTarget)) {
await copyFileChecked(
args.embeddedModuleRoot,
path.join(args.embeddedModuleRoot, metadata.nativeModuleFile),
path.join(filesRoot, 'lib/modules', metadata.nativeModuleFile),
path.join(args.embeddedModuleRoot, module),
path.join(filesRoot, 'lib/modules', module),
);
}
}
Expand Down Expand Up @@ -1031,6 +1057,8 @@ async function writeArtifactDirectory(artifactRoot, args) {
`staticSymbolAliases=${metadata.staticSymbolAliases.map((alias) => `${alias.sqlSymbol}:${alias.linkedSymbol}`).join(',')}`,
`licenseFiles=${licenseFiles.join(',')}`,
`licenseProfile=${licenseProfile}`,
`sqlMembers=${sqlMembers.join(',')}`,
`nativeModuleStems=${sortedDeduped([...modules].map((module) => module.replace(/\.(so|dylib|dll)$/u, ''))).join(',')}`,
'files=files',
'',
].join('\n');
Expand Down
Loading
Loading