Thread: Is there a way to avoid hard coding database connection info into views?
Is there a way to avoid hard coding database connection info into views?
From
Mike Christensen
Date:
I often manually pull in production data into my test database so I can test new code on realistic data, as well as test upgrade scenarios or repro data specific bugs. To do this, I've setup a `VIEW` for each production table in my test database. These views look something like this: CREATE VIEW ProdLink.Users AS select * from dblink( 'hostaddr=123.123.123.123 dbname=ProductionDB user=ROUser password=secret', 'select * from users') as t1(userid uuid, email varchar(50), alias varchar(50), fullname varchar(50), password varchar(100)); Now, on my production database I can run: SELECT * FROM ProdLink.Users; And see all users on my production database. I can then do things like: INSERT INTO Users SELECT * FROM ProdLink.Users L WHERE NOT EXISTS (select 1 from Users where Users.UserId = L.UserId); Allowing me to pull in every user from production that doesn't already exist in test. I have about 30 of these views to *proxy* the production data, however I find it somewhat hacky to have to hardcode in the production database connection info into each view. Is there a good way to avoid hardcoding, or at least duplicating this connection info on each view? Can I use database level variables, environment variables, or anything else instead? PS - I also posted this question on StackOverflow for anyone who wants points: http://stackoverflow.com/questions/10605622/postgres-9-x-is-there-a-way-to-avoid-hard-coding-database-connection-info-into
Re: Is there a way to avoid hard coding database connection info into views?
From
Merlin Moncure
Date:
On Tue, May 15, 2012 at 2:28 PM, Mike Christensen <mike@kitchenpc.com> wrote: > I often manually pull in production data into my test database so I > can test new code on realistic data, as well as test upgrade scenarios > or repro data specific bugs. To do this, I've setup a `VIEW` for each > production table in my test database. These views look something like > this: > > CREATE VIEW ProdLink.Users AS > select * from dblink( > 'hostaddr=123.123.123.123 dbname=ProductionDB user=ROUser > password=secret', > 'select * from users') as t1(userid uuid, email varchar(50), > alias varchar(50), fullname varchar(50), password varchar(100)); > > Now, on my production database I can run: > > SELECT * FROM ProdLink.Users; > > And see all users on my production database. I can then do things like: > > INSERT INTO Users SELECT * FROM ProdLink.Users L WHERE NOT EXISTS > (select 1 from Users where Users.UserId = L.UserId); > > Allowing me to pull in every user from production that doesn't already > exist in test. > > I have about 30 of these views to *proxy* the production data, however > I find it somewhat hacky to have to hardcode in the production > database connection info into each view. > > Is there a good way to avoid hardcoding, or at least duplicating this > connection info on each view? Can I use database level variables, > environment variables, or anything else instead? sure: why don't you set up a named connection and just make sure it's established before hitting any of the views? merlin
Re: Is there a way to avoid hard coding database connection info into views?
From
Mike Christensen
Date:
Thanks! I've never done that in PG before, but I've used named connections with Oracle. Is it the same sort of deal? There's a file on the disk somewhere with the connection info? Either way, I'm sure it's a RTFM thing so I'll look into it. Mike On Tue, May 15, 2012 at 12:45 PM, Merlin Moncure <mmoncure@gmail.com> wrote: > On Tue, May 15, 2012 at 2:28 PM, Mike Christensen <mike@kitchenpc.com> wrote: >> I often manually pull in production data into my test database so I >> can test new code on realistic data, as well as test upgrade scenarios >> or repro data specific bugs. To do this, I've setup a `VIEW` for each >> production table in my test database. These views look something like >> this: >> >> CREATE VIEW ProdLink.Users AS >> select * from dblink( >> 'hostaddr=123.123.123.123 dbname=ProductionDB user=ROUser >> password=secret', >> 'select * from users') as t1(userid uuid, email varchar(50), >> alias varchar(50), fullname varchar(50), password varchar(100)); >> >> Now, on my production database I can run: >> >> SELECT * FROM ProdLink.Users; >> >> And see all users on my production database. I can then do things like: >> >> INSERT INTO Users SELECT * FROM ProdLink.Users L WHERE NOT EXISTS >> (select 1 from Users where Users.UserId = L.UserId); >> >> Allowing me to pull in every user from production that doesn't already >> exist in test. >> >> I have about 30 of these views to *proxy* the production data, however >> I find it somewhat hacky to have to hardcode in the production >> database connection info into each view. >> >> Is there a good way to avoid hardcoding, or at least duplicating this >> connection info on each view? Can I use database level variables, >> environment variables, or anything else instead? > > sure: why don't you set up a named connection and just make sure it's > established before hitting any of the views? > > merlin
Re: Is there a way to avoid hard coding database connection info into views?
From
Merlin Moncure
Date:
On Tue, May 15, 2012 at 2:51 PM, Mike Christensen <mike@kitchenpc.com> wrote: > Thanks! > > I've never done that in PG before, but I've used named connections > with Oracle. Is it the same sort of deal? There's a file on the disk > somewhere with the connection info? Either way, I'm sure it's a RTFM > thing so I'll look into it. yeah, there's a good example in the docs here: http://www.postgresql.org/docs/9.1/static/contrib-dblink-connect.html btw, if you have a structure in test that matches production, then you can use a composite type trick to avoid having to specify fields as long as you keep those structures in sync (which you have to do anyways). try: select (u).* from dblink( 'hostaddr=123.123.123.123 dbname=ProductionDB user=ROUser password=secret', 'select u from users u') as t1(u users); it should work as long as users exists on both sides and has exactly the same structure. using that method it's trivial to make a dblink wrapper that could query any table but you couldn't wrap it into a single view obviously. merlin
Re: Is there a way to avoid hard coding database connection info into views?
From
Mike Christensen
Date:
>> I've never done that in PG before, but I've used named connections >> with Oracle. Is it the same sort of deal? There's a file on the disk >> somewhere with the connection info? Either way, I'm sure it's a RTFM >> thing so I'll look into it. > > yeah, there's a good example in the docs here: > http://www.postgresql.org/docs/9.1/static/contrib-dblink-connect.html > > btw, if you have a structure in test that matches production, then you > can use a composite type trick to avoid having to specify fields as > long as you keep those structures in sync (which you have to do > anyways). try: > > select (u).* from dblink( > 'hostaddr=123.123.123.123 dbname=ProductionDB user=ROUser > password=secret', > 'select u from users u') as t1(u users); > > it should work as long as users exists on both sides and has exactly > the same structure. using that method it's trivial to make a dblink > wrapper that could query any table but you couldn't wrap it into a > single view obviously. Ah ok, now I'm following.. Yea, I had read up on the dblink_connect() function, however it seemed like an extra step to have to open this connection every time. It would avoid duplicating the connection info across multiple views though. What I was hoping for was the ability to store this information somewhere. Doesn't PG allow custom variables for sessions, users, and databases? Or is this something that could be stored in pg_*.conf or as an environment variable? Eventually, this whole thing might evolve into a Python script or something that can migrate data over, and at that point the script could open the connection and migrate the appropriate data over. Also, thanks for the tip using the "users" type rather than explicitly spelling out each column. The majority of my tables are identical in schema, so this would work great. However, sometimes I add new columns in the development schema, and I have to account for that difference on the INSERT line, such as: INSERT INTO Recipes SELECT *, false as SomeNewColumn FROM ProdLink.Recipes WHERE ... So, this may or may not work. Still, good to know! Mike
Re: Is there a way to avoid hard coding database connection info into views?
From
Merlin Moncure
Date:
On Tue, May 15, 2012 at 3:16 PM, Mike Christensen <mike@kitchenpc.com> wrote: >>> I've never done that in PG before, but I've used named connections >>> with Oracle. Is it the same sort of deal? There's a file on the disk >>> somewhere with the connection info? Either way, I'm sure it's a RTFM >>> thing so I'll look into it. >> >> yeah, there's a good example in the docs here: >> http://www.postgresql.org/docs/9.1/static/contrib-dblink-connect.html >> >> btw, if you have a structure in test that matches production, then you >> can use a composite type trick to avoid having to specify fields as >> long as you keep those structures in sync (which you have to do >> anyways). try: >> >> select (u).* from dblink( >> 'hostaddr=123.123.123.123 dbname=ProductionDB user=ROUser >> password=secret', >> 'select u from users u') as t1(u users); >> >> it should work as long as users exists on both sides and has exactly >> the same structure. using that method it's trivial to make a dblink >> wrapper that could query any table but you couldn't wrap it into a >> single view obviously. > > Ah ok, now I'm following.. Yea, I had read up on the dblink_connect() > function, however it seemed like an extra step to have to open this > connection every time. It would avoid duplicating the connection info > across multiple views though. What I was hoping for was the ability > to store this information somewhere. Doesn't PG allow custom > variables for sessions, users, and databases? Or is this something > that could be stored in pg_*.conf or as an environment variable? yes, they are called 'tables' :-). stick your connection string in a table somewhere and do: create view v as select (u).* from dblink((select connstr from yadda where yadda), ...); merlin
Re: Is there a way to avoid hard coding database connection info into views?
From
Mike Christensen
Date:
>>>> I've never done that in PG before, but I've used named connections >>>> with Oracle. Is it the same sort of deal? There's a file on the disk >>>> somewhere with the connection info? Either way, I'm sure it's a RTFM >>>> thing so I'll look into it. >>> >>> yeah, there's a good example in the docs here: >>> http://www.postgresql.org/docs/9.1/static/contrib-dblink-connect.html >>> >>> btw, if you have a structure in test that matches production, then you >>> can use a composite type trick to avoid having to specify fields as >>> long as you keep those structures in sync (which you have to do >>> anyways). try: >>> >>> select (u).* from dblink( >>> 'hostaddr=123.123.123.123 dbname=ProductionDB user=ROUser >>> password=secret', >>> 'select u from users u') as t1(u users); >>> >>> it should work as long as users exists on both sides and has exactly >>> the same structure. using that method it's trivial to make a dblink >>> wrapper that could query any table but you couldn't wrap it into a >>> single view obviously. >> >> Ah ok, now I'm following.. Yea, I had read up on the dblink_connect() >> function, however it seemed like an extra step to have to open this >> connection every time. It would avoid duplicating the connection info >> across multiple views though. What I was hoping for was the ability >> to store this information somewhere. Doesn't PG allow custom >> variables for sessions, users, and databases? Or is this something >> that could be stored in pg_*.conf or as an environment variable? > > yes, they are called 'tables' :-). stick your connection string in a > table somewhere and do: > > create view v as > select (u).* from dblink((select connstr from yadda where yadda), ...); That's definitely an approach. I think I know the possible options anyway. I just wanted to make sure there wasn't anything I was missing. Thanks for your help! Mike