I am trying to connect to a PostGIS database (hosted in a docker container) on a remote server with GRASS. I am able to connect with psql and confirm that the table is there (IP redacted):
psql -h x.x.x.x -U store_sa -d lenistore -p 5432
re -p 5432
psql (12.9 (Ubuntu 12.9-0ubuntu0.20.04.1), server 13.4)
WARNING: psql major version 12, server major version 13.
Some psql features might not work.
Type "help" for help.
lenistore=> select count(*) from store_sa.all_roads;
count
-------
5000
(1 row)
I then make a connection to a table in GRASS:
GRASS 7.8.2 (newLocation):~ > v.external -o input="PG:dbname=lenistore user=store_sa host=x.x.x.x port=5432" layer="store_sa.all_roads" out=network_to_clean --overwrite
Over-riding projection check
WARNING: Vector map <network_to_clean> already exists and will be
overwritten
v.external complete. Link to vector map <network_to_clean> created.
But when I try to run v.clean
, it fails, complaining that the database does not exist.
GRASS 7.8.2 (newLocation):~ > v.clean -c input=network_to_clean output="routing_network" tool=break,chdangl threshold=0.00025,0.0005 --overwrite
Note: In latitude-longitude coordinate system specify threshold in degree
unit
WARNING: Threshold for tool 1 may not be > 0, set to 0
--------------------------------------------------
Tool: Threshold
Break: 0
Change type of boundary dangles: 0.0005
--------------------------------------------------
WARNING: Vector map <routing_network> already exists and will be
overwritten
WARNING: Table <routing_network> linked to vector map <routing_network>
does not exist
DBMI-PostgreSQL driver error:
Connection failed.
FATAL: database "lenistore" does not exist
DBMI-PostgreSQL driver error:
Connection failed.
FATAL: database "lenistore" does not exist
WARNING: Unable to open database <lenistore> by driver <pg>
no database is open
no database is open
WARNING: Unable to copy table <routing_network>
WARNING: Unable to copy table <store_sa.all_roads> for layer 1 from
<network_to_clean@PERMANENT> to <routing_network>
WARNING: Failed to copy attribute table to output vector map
Rebuilding parts of topology...
Building topology for vector map <routing_network@PERMANENT>...
Registering primitives...
--------------------------------------------------
Tool: Split lines
Tool: Break lines at intersections
100%
Tool: Remove duplicates
100%
Tool: Merge lines
100%
--------------------------------------------------
Building topology for vector map <routing_network@PERMANENT>...
--------------------------------------------------
Tool: Change type of boundary dangles
100%
--------------------------------------------------
Rebuilding topology for output vector map...
Building topology for vector map <routing_network@PERMANENT>...
Registering primitives...
I can also confirm that the tables are there by executing v.external -l
:
GRASS 7.8.2 (newLocation):~ > v.external -l input="PG:dbname=lenistore user=store_sa host=x.x.x.x port=5432"
PostGIS database <lenistore> contains 7 feature tables:
store_sa.all_roads
...
I see that I have a psql mismatch, but I don't know if GRASS uses psql or not, and I didn't want to go mucking around too much with that because this server is used by other people. I can try to change it if all else fails but I was hoping that someone could see something simple that I am just completely missing. I tried again with a PostgreSQL 12 image and it still fails for the same reason.
What I find very strange is that when v.clean
executes, it actually seems to go through the process, with the progress bars progressing rather slowly, as if it is processing a large table.
I have also tried altering the user (store_sa) to be SUPERUSER, and even that doesn't work. I am at my wit's end here. It works fine with a local database, only when I connect to this remote one does it fail.
Best Answer
After a very frustrating afternoon with a colleague, we figured it out.
The reason it had always worked before this is because all my code was previously configured to work on a local Postgres instance. (i.e. on localhost).
My explanation here is based on what appears to have happened, I am not an expert on the inner workings on GRASS and my brain feels like a pretzel after this afternoon, so don't take this explanation as the absolute truth.
It seems that
v.external -o input="PG:dbname=lenistore user=store_sa host=x.x.x.x port=5432" layer="store_sa.all_roads" out=network_to_clean --overwrite
does not store the postgres login credentials as part of the created layer, nor does it store the data locally. It is a one-time read of the data, and seems to store it as a layer in your GRASS session which serves as a kind of pointer to the data source.That means that the second command,
v.clean -c input=network_to_clean output="routing_network" tool=break,chdangl threshold=0.00025,0.0005 --overwrite
, has no concept of how to access the database, because it only sees the name of the layer in grass (network_to_clean
), and not the credentials to go actually get the data.We have to run another couple of commands before running
v.clean
:At first I was confused because I thought that
db.login
would perform the action of logging into the database. No - it saves the login credentials to a config file used by GRASS to make future connections. So by running this command first, we seem to save the signature of the login credentials for future uses, similar to a.pgpass
file.So, in short, the full process is:
You probably don't need to run the first two commands every time if this is being executed as a script in the same GRASS context, but it seems to not hurt my process (which is internal and not sensitive, so I don't care), so I'm just leaving it like that.