Connecting to SQL Server from PostgreSQL
Foreign data wrappers enable PostgreSQL to access remote SQL databases. I use TDS foreign data wrapper (tds_fdw on GitHub) to connect PostgreSQL, serving as the Rails database, to a number of remote Microsoft SQL Server databases.
Requirements
PostgreSQL should be version 9.2 or above, and the FreeTDS library should be installed on the database server. In my environment, the SQL Server database versions were 2012 and above.
Connecting to the remote database
After installing TDS foreign data wrapper, follow these steps to connect to the remote SQL Server.
- Create a server that the foreign data wrapper will use to access the remote database:
- Map the foreign server to your PostgreSQL user, for example, your Rails user:
- Create a foreign table. Map the SQL Server data types to their closest PostgreSQL counterparts. Not all fields or attributes from the remote table need to be included.
- Depending on your PostgreSQL security settings, creation of foreign servers (and therefore foreign tables) might be restricted to the root or postgres user. You will need to grant access to the foreign server directly, or just to a foreign table as shown below:
pg_catalog
Head over to the pg_catalog schema of your PostgreSQL database. This schema has information about database extensions, data wrappers, foreign servers and tables.
- pg_extension contains the installed extensions, and you should find a row for tds_fdw
- pg_foreign_data_wrapper has an entry for tds_fdw
- pg_foreign_server and pg_foreign_table have entries for each of the foreign databases and tables you chose to map
The Rails side
Switching from tiny_tds to tds_fdw for my Rails tasks decreased running times from hours to minutes. A drawback is that the code is now written purely in SQL. You might need to write additional tasks to take advantage of Rails features like associations and caching.
You may also want to change your Rails models’ primary and foreign keys to reuse existing table relationships. I plan to discuss this in another post.