2012-12-01 34 views
6

Tôi đang làm việc với API PostgreSQL C. Đọc các documentation nó nói rằng một truy vấn được hoàn thành khi PQgetResult trả về NULL và PQgetResult sẽ chặn nếu PQisBusy không trở về 0. Tuy nhiên PQisBusy trả về 1 nếu không có đầu vào nhiều hơn, vì vậy tôi không thể gọi PQgetResult và nhận được NULL. Vì vậy, tôi không thể biết nếu truy vấn kết thúc. Có cách nào khác để biết nếu truy vấn được thực hiện? Tôi có hiểu nhầm API async không?API Postgres Async phát hiện kết thúc truy vấn

---- chỉnh sửa -----

Ý tưởng cơ bản là mã C là:

PQsendQuery(conn, query) 

while(true) 
{ 
    PQconsumeInput(conn) 
    if(PQisBusy(conn) == 0) 
    { 
     PGresult* res = PQgetResult(conn); 
     if(res) 
     { 
      //print result 
     } 
     else 
     { 
      //res == NULL 
      //indicates query is over 
      break; 
     } 
    } 
} 

Kết quả sẽ được in nhưng vòng lặp không bao giờ chấm dứt. Bởi vì PQisBusy chỉ trả về 0 một lần.

+1

Nó có thể là giá trị cho thịt này ra với mã cho thấy những gì bạn đang làm. –

+0

Tôi nghĩ rằng PQgetResult kiểm tra và đợi tín hiệu bận trước khi trả về kết quả. Vì vậy, có thể không yêu cầu nếu (PQisBusy (conn) == 0) kiểm tra ở tất cả. –

+0

@MuhammadUsama điểm của mã là nó có thể không bao giờ chặn, do đó không đồng bộ. Tôi biết rằng làm I/O không đồng bộ trong một vòng lặp bận là vô nghĩa nhưng tôi cần một ví dụ tối thiểu. – JustMaximumPower

Trả lời

0

Tôi có thể thấy một vấn đề với mã, Bạn không kiểm tra trả về hàm PQconsumeInput (conn). Vì nó là trách nhiệm của PQconsumeInput để xóa bỏ lá cờ bận. Điều gì có thể xảy ra là PQconsumeInput sẽ thất bại mà không cần xử lý bất kỳ dữ liệu nào và xóa bỏ cờ bận.

Tôi nghĩ rằng việc kiểm tra kết quả của PQconsumeInput trước khi gọi PQisBusy sẽ hoạt động tốt.

while (PQconsumeInput(conn) == 1) 
{ 
    if(PQisBusy(conn) == 0) 
    { 
     PGresult* res = PQgetResult(conn); 
     if(res) 
     { 
      //print result 
     } 
     else 
     { 
      //res == NULL 
      //indicates query is over 
      break; 
     } 
    } 
} 
+0

PQconsumeInput trở về 0 chỉ ra một lỗi tài liệu quy định rằng ngay cả trong trường hợp của một lỗi PQgetResult phải được gọi cho đến khi nó trả về NULL. Ngoài ra, một lần nữa, mã trên chỉ là một ví dụ tối giản. Trong mã thực tôi kiểm tra lỗi. – JustMaximumPower

+0

Lưu ý: Ngay cả khi PQresultStatus chỉ ra một lỗi nghiêm trọng, PQgetResult nên được gọi cho đến khi nó trả về một con trỏ null, để cho phép libpq xử lý thông tin lỗi hoàn toàn. –

+0

xin lỗi tôi đã đẩy lại quá sớm và bây giờ tôi không thể chỉnh sửa nhận xét của mình, vì vậy hãy bỏ qua phần trên. Tài liệu nói "Ngay cả khi PQresultStatus chỉ ra một lỗi nghiêm trọng, PQgetResult nên được gọi cho đến khi nó trả về một con trỏ rỗng, để cho phép libpq xử lý thông tin lỗi hoàn toàn." Vì vậy, tôi nghĩ rằng nó chỉ là hợp lệ cho lỗi xảy ra durring PQGetResult chức năng cuộc gọi, không cho lỗi xảy ra trong PQconsumeInput. Cũng trong trường hợp của bạn, bạn đang đợi PQisBusy trả về "không bận" trước khi gọi PQGetResult và tôi tin rằng PQisBusy không thể tin cậy trong trường hợp lỗi được trả về bởi hàm PQconsumeInput. –

1

Dựa trên những gì tôi hiểu từ các liên kết trong nhận xét của tôi, tôi sẽ cố gắng một cái gì đó như thế này (các thông số để select() và các cuộc gọi chức năng khác có thể khá khác nhau):

if (select(sock 1, &input_mask, NULL, NULL, NULL) < 0) { 

    fprintf(stderr, "select() failed: %s\n", strerror(errno)); 
    exit_nicely(conn); 
} 

PQconsumeInput(conn); 

while (PQisBusy(conn) != 0) { 

    /* wait here */ 

} 

while (PGresult* res = PQgetResult(conn)) { /* not sure this is OK, test for not null */ 

    /* do something with res */ 

} 
+0

Điều này không hữu ích. Mã của bạn có thể chặn kể từ khi bạn gọi PQgetResult trong một vòng lặp mà không cần kiểm tra nếu kết nối đang bận. – JustMaximumPower

+0

Vì nó chờ đợi trên 'PQisBusy()' cho đến khi nó không bận rộn nữa và chỉ sau đó gọi 'PQgetResult() ', tôi hoàn toàn không nghĩ vậy. (Tôi có thể sai anyway.) Bạn đã thử điều này? – dezso

+0

Trừ khi tôi hoàn toàn hiểu lầm quan điểm của PQsendQuery thì một truy vấn của tôi được thu thập theo nhiều khối, các mảnh của một bảng lớn. Do đó PQisBusy return 0 không chỉ ra rằng truy vấn kết thúc, trong trường hợp đó câu hỏi của tôi sẽ là tâm trạng, nó chỉ cho thấy rằng một số đầu vào có sẵn. Xác thực mã này bằng cách kiểm tra nó thực sự không phải là một ý tưởng hay; các mã có thể chạy không chặn trong môi trường phòng thí nghiệm nhưng điều đó không bảo đảm rằng mã sẽ không chặn trong sản xuất. – JustMaximumPower

3

Tôi nghĩ những gì bạn cần là PQsetSingleRowMode để cho phép PQgetResult trả lại một hàng mỗi lần.

từ http://www.postgresql.org/docs/9.2/static/libpq-single-row-mode.html

Thông thường, libpq thu thập toàn bộ kết quả một lệnh SQL và trả nó vào ứng dụng như một PGresult duy nhất. Điều này có thể không hoạt động đối với các lệnh trả về một số lượng lớn hàng. Đối với các trường hợp như vậy, các ứng dụng có thể sử dụng PQsendQuery và PQgetResult ở chế độ một hàng. Trong chế độ này, (các) hàng kết quả được trả về ứng dụng một tại một lần, khi chúng được nhận từ máy chủ.

Nếu truy vấn trả về bất kỳ hàng nào, chúng sẽ được trả về dưới dạng đối tượng PGresult riêng lẻ, trông giống như kết quả truy vấn bình thường ngoại trừ có mã trạng thái PGRES_SINGLE_TUPLE thay vì PGRES_TUPLES_OK. Sau hàng cuối cùng, hoặc ngay lập tức nếu truy vấn trả về 0 hàng, một đối tượng không có hàng với trạng thái PGRES_TUPLES_OK được trả về; đây là tín hiệu không còn hàng nào nữa.

kiểm tra ra các mẫu mã: https://github.com/markokr/libpq-rowproc-demos/blob/master/demo-onerow-async.c

+0

Mã mẫu bạn đã liên kết để đánh giá giá trị trả về của PQresultStatus để xác định xem truy vấn đã kết thúc chưa. Tôi không thích phong cách đó, nhưng tôi đoán đó là giải pháp tốt nhất cho đến nay. Do đó tôi sẽ cung cấp cho bạn tiền thưởng, trước khi nó bị mất. – JustMaximumPower

Các vấn đề liên quan