Acabei não usando nenhuma ferramenta de terceiros para os dados, pois nenhum dos que eu tentei funcionou nas grandes tabelas. Mesmo SSIS falhou. Eu usei uma ferramenta comercial para o esquema, no entanto. Então, meu processo de conversão foi o seguinte:
- Full Convert Enterprise para copiar o esquema (sem dados).
- pg_dump para exportar os dados do Postgres no formato "texto simples", que é basicamente um arquivo de valores separados por tabulação (TSV).
- Os scripts em Python para transformar os arquivos exportados em um formato que o bcp entenderia.
- bcp para importar os dados para o MSSQL.
A etapa de transformação cuidou de algumas diferenças nos formatos usados pelo pg_dump e bcp, como:
- O pg_dump coloca algumas coisas específicas do Postgres no início do arquivo e finaliza os dados com ".", enquanto o bcp espera que o arquivo inteiro contenha dados
- pg_dump armazena valores NULL como "\ N", enquanto o bcp não espera nada no lugar de um NULL (ou seja, nenhum dado entre os separadores de colunas)
- pg_dump codifica as guias como "\ t" e novas linhas como "\ n", enquanto o bcp as trata literalmente
- pg_dump sempre usa abas e novas linhas como separadores, enquanto o bcp permite ao usuário especificar separadores. Isso se torna necessário se os dados contiverem guias ou novas linhas, uma vez que não estão codificados.
Eu também descobri que algumas restrições únicas que estavam bem no Postgres foram violadas no MSSQL, então eu tive que descartá-las. Isso ocorreu porque NULL = NULL no MSSQL (ou seja, NULL é tratado como um valor único), mas não no Postgres.