Created
June 2, 2025 16:28
-
-
Save stelf/03cbea1ce7de2fb248f6abb49dc252a9 to your computer and use it in GitHub Desktop.
feed data using the best ogr that supports pg. windows11 version onyl.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# PowerShell script: Find ogr2ogr.exe, check PostgreSQL support, build DSN from .env, and import shapefile | |
# Enhanced version with proper handling for unnamed geometry columns | |
param( | |
[string]$inputFile = "data\cadaster_all.shp", | |
[string]$table = $([System.IO.Path]::GetFileNameWithoutExtension($inputFile)), # Infer from input file | |
[ValidateSet("auto", "sql", "select", "geometry")] | |
[string]$geometryMode = "auto", | |
[switch]$overwrite, | |
[string[]]$selectedColumns = @("*"), # Default to all columns | |
[string]$sourceLayer # Will be inferred if not provided | |
) | |
function Get-SourceLayerName { | |
param( | |
[string]$filePath, | |
[string]$ogrinfoPath | |
) | |
try { | |
# Use -so (summary only) to get just the layer name, capture all output | |
# Ensure the command is executed and output is captured correctly | |
$ogrinfoOutput = & $ogrinfoPath $filePath -so 2>&1 | |
# Debugging: Print raw output | |
Write-Host -ForegroundColor DarkYellow "Raw ogrinfo output for layer detection:" | |
$ogrinfoOutput | ForEach-Object { Write-Host -ForegroundColor DarkYellow $_ } | |
# Iterate through each line of output to find the layer name | |
foreach ($line in $ogrinfoOutput) { | |
if ($line -match '^1: (.+) \(.*\)$') { | |
return $Matches[1].Trim() | |
} | |
} | |
} catch { | |
Write-Warning "Could not determine source layer name for '$filePath': $($_.Exception.Message)" | |
} | |
return $null | |
} | |
function Get-EnvFile { | |
$dir = Get-Location | |
while ($null -ne $dir) { | |
$envPath = Join-Path $dir ".env" | |
if (Test-Path $envPath) { return $envPath } | |
$parent = Split-Path $dir -Parent | |
if ($parent -eq $dir) { break } | |
$dir = $parent | |
} | |
return $null | |
} | |
function Get-DSNVars { | |
param($envFile) | |
$vars = @{ | |
PGUSER = $null | |
PGPASSWORD = $null | |
PGHOST = $null | |
PGDATABASE = $null | |
PGPORT = "5432" | |
} | |
Get-Content $envFile | ForEach-Object { | |
if ($_ -match '^\s*PGUSER\s*=\s*(.+)$') { $vars.PGUSER = $Matches[1].Trim() } | |
elseif ($_ -match '^\s*PGPASSWORD\s*=\s*(.+)$') { $vars.PGPASSWORD = $Matches[1].Trim() } | |
elseif ($_ -match '^\s*PGHOST\s*=\s*(.+)$') { $vars.PGHOST = $Matches[1].Trim() } | |
elseif ($_ -match '^\s*PGDATABASE\s*=\s*(.+)$') { $vars.PGDATABASE = $Matches[1].Trim() } | |
elseif ($_ -match '^\s*PGPORT\s*=\s*(.+)$') { $vars.PGPORT = $Matches[1].Trim() } | |
} | |
return $vars | |
} | |
# Find OGR executables with PostgreSQL support | |
$ogr2ogrPg = $null | |
$ogrinfoPg = $null | |
# Try to use cached values first | |
if ($env:OGR2OGR_PG_PATH -and (Test-Path $env:OGR2OGR_PG_PATH)) { | |
$ogr2ogrPg = $env:OGR2OGR_PG_PATH | |
} | |
if ($env:OGRINFO_PG_PATH -and (Test-Path $env:OGRINFO_PG_PATH)) { | |
$ogrinfoPg = $env:OGRINFO_PG_PATH | |
} | |
if (-not $ogr2ogrPg -or -not $ogrinfoPg) { | |
Write-Host -ForegroundColor Magenta "Looking for ogr2ogr.exe and ogrinfo.exe with proper PostgreSQL driver support" | |
$ogrExecutables = @("ogr2ogr.exe", "ogrinfo.exe") | |
$foundPaths = @{} | |
foreach ($exe in $ogrExecutables) { | |
$paths = @() | |
if (Get-Command fd -ErrorAction SilentlyContinue) { | |
$paths = fd $exe -tx / | Where-Object { $_ -match "$exe$" } | |
} else { | |
$paths = Get-ChildItem -Path C:\ -Filter $exe -Recurse -ErrorAction SilentlyContinue | Select-Object -ExpandProperty FullName | |
} | |
if ($paths) { | |
Write-Host -ForegroundColor Magenta "Found few '$exe' instances, lets verify driver" | |
$pgSupportedPath = $paths | Where-Object { | |
(& $_ --formats 2>&1) -match 'PostgreSQL -vector-' | |
} | Select-Object -First 1 | |
if ($pgSupportedPath) { | |
$foundPaths[$exe] = $pgSupportedPath | |
Write-Host -ForegroundColor Green "Found PostgreSQL-enabled '$exe': $pgSupportedPath" | |
} else { | |
Write-Warning "No PostgreSQL-enabled '$exe' found among discovered paths." | |
} | |
} else { | |
Write-Warning "No '$exe' found on the system." | |
} | |
} | |
$ogr2ogrPg = $foundPaths["ogr2ogr.exe"] | |
$ogrinfoPg = $foundPaths["ogrinfo.exe"] | |
if ($ogr2ogrPg) { | |
$env:OGR2OGR_PG_PATH = $ogr2ogrPg # Cache for future runs | |
} | |
if ($ogrinfoPg) { | |
$env:OGRINFO_PG_PATH = $ogrinfoPg # Cache for future runs | |
} | |
} | |
if (-not $ogr2ogrPg) { | |
Write-Error "No ogr2ogr.exe with PostgreSQL support found." | |
exit 2 | |
} | |
if (-not $ogrinfoPg) { | |
Write-Error "No ogrinfo.exe with PostgreSQL support found." | |
exit 6 # New exit code for ogrinfo missing | |
} | |
# Infer source layer name if not provided | |
if (-not $sourceLayer) { | |
$sourceLayer = Get-SourceLayerName -filePath $inputFile -ogrinfoPath $ogrinfoPg | |
if (-not $sourceLayer) { | |
Write-Error "Could not determine source layer name. Please specify it using -sourceLayer parameter." | |
exit 5 | |
} | |
} | |
# Build DSN from .env | |
$envFile = Get-EnvFile | |
if (-not $envFile) { | |
Write-Error ".env file not found." | |
exit 3 | |
} | |
$pgVars = Get-DSNVars $envFile | |
if (-not $pgVars.PGUSER -or -not $pgVars.PGHOST -or -not $pgVars.PGDATABASE) { | |
Write-Error "Missing PGUSER, PGPASSWORD, PGHOST, or PGDATABASE in .env." | |
exit 4 | |
} | |
$dsn = "postgresql://$($pgVars.PGUSER):$($pgVars.PGPASSWORD)@$($pgVars.PGHOST):$($pgVars.PGPORT)/$($pgVars.PGDATABASE)" | |
# Summarize | |
Write-Host -ForegroundColor Cyan "Preparing to run ogr2ogr with the following parameters:" | |
$configSummary = [PSCustomObject]@{ | |
"Input File" = $inputFile | |
"Target Table" = $table | |
"Source Layer" = $sourceLayer | |
"Geometry Mode" = $geometryMode | |
"Overwrite" = $overwrite | |
"Selected Columns" = ($selectedColumns -join ", ") | |
"PostgreSQL DSN" = "postgresql://$($pgVars.PGUSER):<password_hidden>@$($pgVars.PGHOST):$($pgVars.PGPORT)/$($pgVars.PGDATABASE)" | |
} | |
$configSummary | Format-Table -AutoSize | |
# Build common ogr2ogr parameters | |
$commonParams = @( | |
"-progress" | |
"-f", "PostgreSQL" | |
"PG:$dsn" | |
$inputFile | |
"-nln", $table | |
"-lco", "GEOMETRY_NAME=geom" | |
"-lco", "FID=id" | |
"-nlt", "PROMOTE_TO_MULTI" # Ensure correct geometry type handling | |
) | |
# Add overwrite flag if specified | |
if ($overwrite) { | |
$commonParams += "-overwrite" | |
Write-Host -ForegroundColor Yellow "Table will be overwritten if it exists" | |
} | |
# Execute the ogr2ogr command based on geometry mode | |
switch ($geometryMode) { | |
"auto" { | |
Write-Host -ForegroundColor Yellow "Using auto mode - let ogr2ogr handle geometry and all attributes automatically" | |
Write-Host $ogr2ogrPg @commonParams $sourceLayer | |
&$ogr2ogrPg @commonParams $sourceLayer | |
} | |
"sql" { | |
Write-Host -ForegroundColor Yellow "Using SQL mode - explicitly selecting specified fields with geometry" | |
if ($selectedColumns -contains "*") { | |
&$ogr2ogrPg @commonParams -sql "SELECT * FROM `"$sourceLayer`"" $sourceLayer | |
} else { | |
$columnList = $selectedColumns -join ", " | |
&$ogr2ogrPg @commonParams -sql "SELECT $columnList FROM `"$sourceLayer`"" $sourceLayer | |
} | |
} | |
"select" { | |
Write-Host -ForegroundColor Yellow "Using select mode - selecting specified fields only" | |
if ($selectedColumns -contains "*") { | |
# -select with * is not standard, so we'll just use auto behavior | |
Write-Host -ForegroundColor Yellow "Warning: '-select *' is not directly supported. Using auto mode behavior for attribute selection." | |
&$ogr2ogrPg @commonParams $sourceLayer | |
} else { | |
$columnList = $selectedColumns -join "," | |
&$ogr2ogrPg @commonParams -select $columnList $sourceLayer | |
} | |
} | |
"geometry" { | |
Write-Host -ForegroundColor Yellow "Using geometry mode - for completely unnamed geometry columns, importing all attributes" | |
&$ogr2ogrPg @commonParams -sql "SELECT *, GEOMETRY FROM `"$sourceLayer`"" $sourceLayer | |
} | |
} | |
Write-Host -ForegroundColor Green "ogr2ogr command completed." | |
# Additional notes for handling unnamed geometry columns: | |
<# | |
HANDLING UNNAMED GEOMETRY COLUMNS IN OGR2OGR: | |
1. AUTO MODE (-geometryMode auto): | |
- Uses -select parameter to let ogr2ogr auto-detect geometry | |
- Works when geometry column exists but may not have a proper name | |
- Recommended for most standard shapefiles | |
2. SQL MODE (-geometryMode sql): | |
- Uses -sql parameter with explicit SELECT statement | |
- Geometry is automatically included when using SQL | |
- Good for complex field selection scenarios | |
3. SELECT MODE (-geometryMode select): | |
- Uses -select parameter with specific field names | |
- Geometry is handled automatically by ogr2ogr | |
- Similar to auto but more explicit about field selection | |
4. GEOMETRY MODE (-geometryMode geometry): | |
- Uses -sql with explicit GEOMETRY reference | |
- For cases where geometry column is completely unnamed | |
- Uses "SELECT *, GEOMETRY FROM layer_name" syntax | |
COMMON ISSUES AND SOLUTIONS: | |
- If geometry column has no name: Use -geometryMode geometry | |
- If you get "geometry column not found": Try -geometryMode auto first | |
- For complex queries: Use -geometryMode sql with custom SQL | |
- For simple field selection: Use -geometryMode select | |
ADDITIONAL OGR2OGR OPTIONS FOR GEOMETRY HANDLING: | |
- -lco GEOMETRY_NAME=geom: Sets the target geometry column name | |
- -nlt PROMOTE_TO_MULTI: Promotes geometries to multi-type (handles mixed geometry types) | |
- -t_srs EPSG:4326: Transform to specific coordinate system if needed | |
- -s_srs EPSG:xxxx: Specify source coordinate system if not detected | |
- -dim XY: Force 2D geometry (removes Z coordinates) | |
PROJ DATABASE ERROR: | |
If you encounter "proj_identify: ... DATABASE.LAYOUT.VERSION.MINOR = 2 whereas a number >= 4 is expected", | |
it means you have multiple PROJ installations or an outdated one. | |
You might need to set the PROJ_LIB environment variable to point to the correct PROJ database: | |
$env:PROJ_LIB = "C:\Path\To\Your\Preferred\PROJ\share" | |
USAGE EXAMPLES: | |
.\ogr.feed.data.ps1 -geometryMode auto | |
.\ogr.feed.data.ps1 -geometryMode sql -inputFile "data\other.shp" -table "other_table" | |
.\ogr.feed.data.ps1 -geometryMode geometry # For completely unnamed geometry columns | |
#> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment