Microsoft MVP성태의 닷넷 이야기
개발 환경 구성: 90. 닷넷에서 접근해보는 PostgreSQL DB [링크 복사], [링크+제목 복사]
조회: 90099
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 
(연관된 글이 4개 있습니다.)
닷넷에서 접근해보는 PostgreSQL DB

드디어, "PostgreSQL" 데이터베이스를 사용하고 있는 예비 고객사에서 ^^ "제니퍼 닷넷 APM 솔루션"에서 PostgreSQL DB 접근에 대한 모니터링이 가능한지 문의가 들어왔습니다. 그래서 이렇게 PostgreSQL을 처음 설치하고 만져보았는데요. 오호~~~ "관계형 데이터베이스"들이 SQL 쿼리를 지원하고 닷넷의 경우에는 .NET Data Provider를 위한 인터페이스들이 강제되어 있다 보니 기본적인 사용법이 그다지 어렵지 않더군요.

물론, 제가 바닥부터 ^^ PostgreSQL 접근을 알아본 것은 아니고 아래의 글에서부터 시작을 했습니다.

Using PostgreSQL in your C# (.NET) application (An introduction)
; http://www.codeproject.com/KB/database/afppostgresqlintro.aspx

당연히 PostgreSQL 데이터베이스를 서버에 설치부터 해야할텐데, 다음의 경로에서 윈도우 버전의 설치 파일을 다운로드 할 수 있습니다.

Download PostgreSQL 
; http://www.enterprisedb.com/products/pgdownload.do#windows

제 경우에는 x64 운영체제에 설치하기 때문에 "Win x86-64" 아이콘을 눌러서 다운로드 받은 후 설치를 했습니다. 다행히 설치는 무척 간단합니다. ^^ 여느 DB처럼, superuser를 위한 암호를 묻고, 기본 접속 포트는 5432로 설치를 마친 후 SQL 서버의 "Management Studio"와 같은 도구와 유사한 "시작" / "PostgreSQL 9.0" / "pgAdmin III" 프로그램을 실행해서 GUI 환경에서 관리를 해줄 수 있습니다.

관리방식도 꽤 직관적입니다. 누구나 한번쯤 아래와 같이 "오른쪽 마우스 버튼"을 눌러서 "Connect"를 실행해 볼 것이고,

postgresql_dotnet_1.png

설치 시 입력했던 관리자 암호를 입력한 후,

postgresql_dotnet_2.png

연결 문자열에 사용할 테스트용 사용자 계정(ID: testuser)을 아래와 같이 "Login Roles" 노드에서 생성할 수 있습니다.

postgresql_dotnet_3.png

"Database" 노드에서는 새로운 DB를 생성(Name: testdb, Owner: testuser)해 줄 수 있고,

postgresql_dotnet_4.png

생성된 "testdb" 하위 노드의 "Schemas / public / Tables" 에서 테이블을 생성할 수 있습니다.

postgresql_dotnet_5.png

Name: TestTable
Owner: testuser


"New Table..." 대화창의 "Columns" 탭에서 "Add" 버튼을 눌러 다음과 같이 "칼럼"을 추가해 주는 것으로 테스트 환경 구축은 거의 완료가 됩니다.

postgresql_dotnet_6.png

tid: bigserial NOT NULL
name: character varying(150) NOT NULL
age: integer NOT NULL


Primary Key는 "TestTable" 노드를 마우스 오른쪽 버튼 클릭해서 "New Object" / "New Primary Key" 메뉴 선택으로 지정해 줄 수 있습니다. 그 외에 SQL Server와의 변환 체계는 다음의 글을 참고하시면 되겠습니다.

Conversion of Microsoft SQL/ASP applications to PostgreSQL
; http://wiki.postgresql.org/images/e/e4/5.pdf




설치 및 테스트용 DB 구성을 정상적으로 서버에서 마쳤으면, 이제 개발자 PC에 PostgreSQL 서버를 위한 ".NET Data Provider"를 다운로드 받아야 하는데, 다음의 경로에서 C#으로 구현된 오픈소스 "Npgsql"을 구할 수 있습니다.

Npgsql - a .Net data provider for Postgresql
; http://pgfoundry.org/projects/npgsql

다운로드 Npgsql
; http://pgfoundry.org/frs/?group_id=1000140&release_id=958

Microsoft .NET Framework을 위해서 3가지 링크가 제공되는데요.

  1. Npgsql2.0.11-bin-ms.net.zip 464 KB 1,540 Any .zip
  2. Npgsql2.0.11-bin-ms.net3.5sp1.zip 511 KB 1,393 Any .zip
  3. Npgsql2.0.11-bin-ms.net4.0.zip

음... 2번과 3번의 차이는 쉽게 알겠는데 1번은 왜 있는지 잘 모르겠군요. 그냥 무시하고 ^^ 2번과 3번 중에서 원하는 것을 받아 압축을 해제한 후, 다음의 2개 파일만 여러분들의 웹 사이트 프로젝트에 복사해서 참조를 하시면 됩니다. (또는 GAC에 등록을 해주거나.)

  • Mono.Security.dll
  • Npgsql.dll

이렇게 마치고, 처음 연결문자열을 다음과 같이 설정하고 접속을 했는데,

string connectionString = "Server=testpc;Port=5432;User Id=testuser;Password=testuser;Database=testdb";
using (NpgsqlConnection connection = new NpgsqlConnection())
{
    connection.ConnectionString = connectionString;
    connection.Open();

지금까지 너무 쉽긴 했지요. ^^; 아래와 같이 오류가 발생합니다.

System.IO.IOException occurred
  Message=Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
  Source=System
  StackTrace:
       at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
       at System.IO.BufferedStream.ReadByte()
       at Npgsql.NpgsqlState.<ProcessBackendResponses_Ver_3>d__a.MoveNext() in C:\...\NpgsqlState.cs:line 665
  InnerException: System.Net.Sockets.SocketException
       Message=An existing connection was forcibly closed by the remote host
       Source=System
       ErrorCode=10054
       NativeErrorCode=10054
       StackTrace:
            at System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags)
            at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
       InnerException: 

기본값이 SSL 연결만 허용하기 때문인데, "pgAdmin III" 도구에서 "Tools" / "Server Configuration" / "postgresql.conf" 메뉴를 선택하고 아래와 같이 "SSL off" 옵션을 허용시켜 주면 됩니다.

postgresql_dotnet_7.png

아니... ^^; 그래도 다음과 같이 오류가 발생하더군요.

Npgsql.NpgsqlException was unhandled by user code
  Message=FATAL: 28000: no pg_hba.conf entry for host "192.168.0.132", user "testuser", database "testdb", SSL off
  Source=Npgsql
  ErrorCode=-2147467259
  BaseMessage=no pg_hba.conf entry for host "192.168.0.132", user "testuser", database "testdb", SSL off
  Code=28000
  Detail=""
  ErrorSql=""
  File=.\src\backend\libpq\auth.c
  Hint=""
  Line=464
  Position=""
  Routine=ClientAuthentication
  Severity=FATAL
  Where=""
  StackTrace:
       at Npgsql.NpgsqlState.<ProcessBackendResponses_Ver_3>d__a.MoveNext() in C:\...\NpgsqlState.cs:line 686
       at Npgsql.NpgsqlState.IterateThroughAllResponses(IEnumerable`1 ienum) in C:\...\NpgsqlState.cs:line 319
       at Npgsql.NpgsqlState.ProcessBackendResponses(NpgsqlConnector context) in C:\...\NpgsqlState.cs:line 314
       at Npgsql.NpgsqlConnectedState.Startup(NpgsqlConnector context) in C:\...\NpgsqlConnectedState.cs:line 52
       at Npgsql.NpgsqlConnector.Open() in C:\...\NpgsqlConnector.cs:line 656
       at Npgsql.NpgsqlConnectorPool.GetPooledConnector(NpgsqlConnection Connection) in C:\...\NpgsqlConnectorPool.cs:line 423
       at Npgsql.NpgsqlConnectorPool.RequestPooledConnectorInternal(NpgsqlConnection Connection) in C:\...\NpgsqlConnectorPool.cs:line 226
       at Npgsql.NpgsqlConnectorPool.RequestPooledConnector(NpgsqlConnection Connection) in C:\...\NpgsqlConnectorPool.cs:line 178
       at Npgsql.NpgsqlConnectorPool.RequestConnector(NpgsqlConnection Connection) in C:\...\NpgsqlConnectorPool.cs:line 158
       at Npgsql.NpgsqlConnection.Open() in C:\...\NpgsqlConnection.cs:line 543
       at Jennifer40.WebSiteTest.postgreSQLTest.Page_Load(Object sender, EventArgs e) in D:\workshop\Jennifer\Sources\Agent\UnitTest\Jennifer40.WebSiteTest\postgreSQLTest.aspx.cs:line 23
       at System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e)
       at System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e)
       at System.Web.UI.Control.OnLoad(EventArgs e)
       at System.Web.UI.Control.LoadRecursive()
       at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
  InnerException: 

음... 용서해줄 수 있습니다. 기본적인 "Lockdown" 보안 정책은 충분히 이해해 줄 수 있거든요. ^^

검색을 해보니까, PostgreSQL 서버는 접속하려는 측의 IP를 별도로 등록해 주거나, 모든 IP로부터의 접속을 허용한다는 식의 설정을 명시적으로 해주어야 한다고 나옵니다.

그래서, "pgAdmin III" 도구에서 "Tools" / "Server Configuration" / "pg_hba.conf" 메뉴를 선택하고 다음과 같이 NpgsqlConnection 개체를 사용하는 클라이언트 측의 컴퓨터 IP를 등록해 주었습니다.

postgresql_dotnet_8.png

host testdb all 192.168.0.132/32 md5


보시는 것처럼 CIDR 방식으로 지정하는 것이 가능하기 때문에, 일정한 IP 대역을 선택하는 것도 가능합니다. 예를 들어, 다음과 같이 해주면 192.168.0.*의 모든 컴퓨터로부터 접속을 허용합니다.

host     testdb  all     192.168.0.0/24  md5

설정을 변경한 후에는 "서비스 관리자"에서 "postgresql-x64-9.0" NT 서비스를 재시작 해주어야 합니다.

기타의 보다 자세한 사항은 다음의 문서를 보시면 도움이 될 것입니다. ^^

PostgreSQL 8.1.22 Documentation
- Chapter 20. Client Authentication
; http://www.postgresql.org/docs/8.1/interactive/client-authentication.html

물론, 이렇게 적용하고 난 후에는 정상적으로 NpgsqlConnection 연결이 되었고 그 외의 NpgsqlCommand, NpgsqlParameter, NpgsqlDataReader 개체는 아래의 예제 코드에서 보는 것처럼, 예의 "@MyParam"이 아닌 ":MyParam"과 같이 파라미터를 지원하는 차이만을 제외하고는 늘 해오던 수준에서 해결이 되었습니다.

using (NpgsqlConnection connection = new NpgsqlConnection())
{
    connection.ConnectionString = connectionString;
    connection.Open();

    NpgsqlCommand command = new NpgsqlCommand();

    command.Connection = connection;
    command.CommandText = "SELECT * FROM TestTable WHERE :MyParam is not null";
    command.Parameters.Add(new NpgsqlParameter("MyParam", "test"));

    NpgsqlDataReader reader = command.ExecuteReader();
    if (reader != null)
    {
        while (reader.Read())
        {
        }

        reader.Close();
    }
}




한가지, 시행착오를 더 설명드려야겠군요. ^^

"pgAdmin III" 도구에서 테이블 명을 "TestTable"과 같이 대소문자를 섞어서 지정한 경우 다음과 같은 쿼리를 NpgsqlCommand 개체에 지정해서 실행하면 오류가 발생합니다.

SELECT * FROM TestTable

오류 내용은 다음과 같습니다.

Npgsql.NpgsqlException was unhandled by user code
  Message=ERROR: 42P01: relation "testtable" does not exist
  Source=Npgsql
  ErrorCode=-2147467259
  BaseMessage=relation "testtable" does not exist
  Code=42P01
  Detail=""
  ErrorSql=SELECT * FROM TestTable WHERE ((E'test')) is not null AND 1 = 1 AND 'A' = 'A'
  File=.\src\backend\parser\parse_relation.c
  Hint=""
  Line=857
  Position=15
  Routine=parserOpenTable
  Severity=ERROR
  Where=""
  StackTrace:
  ...[생략]...
       at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
  InnerException: 

해답은 아래에서 찾아보니 나오는데요.

Re: Database, Table Names are resulting in lowercase
; http://archives.postgresql.org/pgsql-admin/2004-06/msg00324.php

명시적으로 "쿼리문"에 포함된 테이블명을 대소문자로 인식시키려면 다음과 같이 쿼리를 바꿔주어야 합니다.

SELECT * FROM "TestTable"

C#의 경우, 아래와 같이 설정됩니다.

command.CommandText = "SELECT * FROM \"TestTable\"";

아니면, 그냥 속편하게 "pgAdmin III" 도구에서 테이블 생성할 때 소문자로만 이름을 줘도 되겠고.




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 6/28/2023]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 



2012-02-14 11시37분
위의 글에서 "Npgsql2.0.11-bin-ms.net.zip" 파일의 용도를 모르겠다고 했는데... 차이점을 알았습니다. ^^ 그 파일은 순수하게 .NET 2.0 Framework 만 설치된 경우에 사용할 수 있습니다. "2.Npgsql2.0.11-bin-ms.net3.5sp1.zip"에 포함된 Npgsql.dll 은 .NET 3.5 에서만 배포되는 System.Data.Entity.dll 어셈블리를 참조하고 있다는 차이가 있습니다.
정성태
2015-12-01 12시33분
[gwise] 테이블 대소문자 관련 내용이 "PostgreSQL for Data Architects" 책의 210 page에도 나와 있어서 덧글 남기고 갑니다.
테이블 생성할때 대문자나 소문자 하나로 통일하고 쿼리로 사용할때는 대소문자 섞어서 사용해도 됩니다.(이게 좀 귀찮긴 하네요)
닷넷 관련 내용 잘 보고 있습니다.
[guest]
2015-12-01 01시01분
그러게요. 살짝 귀찮긴 하지만 저 정도는 감수해도 무방할 듯 합니다. ^^
정성태
2015-12-01 04시08분
[gwise] GUI툴로 테이블 만들어 내는 쿼리를 보니 대소문자 구분할때는 위에 말씀하신 바와 같이 쌍따옴표가 있습니다.
그러나 쿼리에서 직접 쌍따옴표 없이 대소문자 같이 있는 스크립트로 테이블을 만드니 전부 소문자로 생성이 되네요.
결국 원인은 테이블 생성할때의 차이때문인거 같습니다.

그리고 아래와 같이 두개 테이블 쿼리에서 생성하면 두개 다 생성이 됩니다.
CREATE TABLE Mytb (Id integer ) <- 얘는 실제로는 전부 소문자로 생성됨.
CREATE TABLE "Mytb" ("Id" integer ) <- GUI에서 테이블 생성하면 이렇게 query됨.

Postgresql 테이블이나 컬럼 생성할때 맘편하게 소문자로 하는게 정신건강에 좋을거 같습니다. ^^
[guest]
2021-08-06 09시37분
정성태

1  2  3  4  5  6  7  8  [9]  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
13395정성태7/20/20233305개발 환경 구성: 685. 로컬에서 개발 중인 ASP.NET Core/5+ 웹 사이트에 대해 localhost 이외의 호스트 이름으로 접근하는 방법
13394정성태7/16/20233249오류 유형: 873. Oracle.ManagedDataAccess.Client - 쿼리 수행 시 System.InvalidOperationException
13393정성태7/16/20233413닷넷: 2133. C# - Oracle 데이터베이스의 Sleep 쿼리 실행하는 방법
13392정성태7/16/20233278오류 유형: 872. Oracle - ORA-01031: insufficient privileges
13391정성태7/14/20233366닷넷: 2132. C# - sealed 클래스의 메서드를 callback 호출했을 때 인라인 처리가 될까요?
13390정성태7/12/20233337스크립트: 53. 파이썬 - localhost 호출 시의 hang 현상
13389정성태7/5/20233319개발 환경 구성: 684. IIS Express로 호스팅하는 웹을 WSL 환경에서 접근하는 방법
13388정성태7/3/20233504오류 유형: 871. 윈도우 탐색기에서 열리지 않는 zip 파일 - The Compressed (zipped) Folder '[...].zip' is invalid. [1]파일 다운로드1
13387정성태6/28/20233530오류 유형: 870. _mysql - Commands out of sync; you can't run this command now
13386정성태6/27/20233600Linux: 61. docker - 원격 제어를 위한 TCP 바인딩 추가
13385정성태6/27/20233799Linux: 60. Linux - 외부에서의 접속을 허용하기 위한 TCP 포트 여는 방법
13384정성태6/26/20233557.NET Framework: 2131. C# - Source Generator로 해결하는 enum 박싱 문제파일 다운로드1
13383정성태6/26/20233307개발 환경 구성: 683. GPU 런타임을 사용하는 Colab 노트북 설정
13382정성태6/25/20233346.NET Framework: 2130. C# - Win32 API를 이용한 윈도우 계정 정보 (예: 마지막 로그온 시간)파일 다운로드1
13381정성태6/25/20233730오류 유형: 869. Fatal Python error: init_fs_encoding: failed to get the Python codec of the filesystem encoding
13380정성태6/24/20233193스크립트: 52. 파이썬 3.x에서의 동적 함수 추가
13379정성태6/23/20233205스크립트: 51. 파이썬 2.x에서의 동적 함수 추가
13378정성태6/22/20233093오류 유형: 868. docker - build 시 "CANCELED ..." 뜨는 문제
13377정성태6/22/20236857오류 유형: 867. 파이썬 mysqlclient 2.2.x 설치 시 "Specify MYSQLCLIENT_CFLAGS and MYSQLCLIENT_LDFLAGS env vars manually" 오류
13376정성태6/21/20233282.NET Framework: 2129. C# - Polly를 이용한 클라이언트 측의 요청 재시도파일 다운로드1
13375정성태6/20/20232977스크립트: 50. Transformers (신경망 언어모델 라이브러리) 강좌 - 2장 코드 실행 결과
13374정성태6/20/20233106오류 유형: 866. 파이썬 - <class 'AttributeError'> module 'flask.json' has no attribute 'JSONEncoder'
13373정성태6/19/20234395오류 유형: 865. 파이썬 - pymssql 설치 관련 오류 정리
13372정성태6/15/20233103개발 환경 구성: 682. SQL Server TLS 통신을 위해 사용되는 키 길이 확인 방법
13371정성태6/15/20233109개발 환경 구성: 681. openssl - 인증서 버전(V1 / V3)
13370정성태6/14/20233288개발 환경 구성: 680. C# - Ubuntu + Microsoft.Data.SqlClient + SQL Server 2008 R2 연결 방법 - TLS 1.2 지원
1  2  3  4  5  6  7  8  [9]  10  11  12  13  14  15  ...