33
33
#include <arpa/inet.h>
34
34
#endif
35
35
36
+ #include "common/pg_lzcompress.h"
37
+ #include "utils/elog.h"
36
38
37
39
/*
38
40
* This macro lists the backend message types that could be "long" (more
39
41
* than a couple of kilobytes).
40
42
*/
41
43
#define VALID_LONG_MESSAGE_TYPE (id ) \
42
- ((id) == 'T' || (id) == 'D' || (id) == 'd' || (id) == 'V' || \
44
+ ((id) == 'T' || (id) == 'D' || (id) == 'd' || (id) == 'z' || (id) == ' V' || \
43
45
(id) == 'E' || (id) == 'N' || (id) == 'A')
44
46
45
47
@@ -389,6 +391,7 @@ pqParseInput3(PGconn *conn)
389
391
conn -> copy_already_done = 0 ;
390
392
break ;
391
393
case 'd' : /* Copy Data */
394
+ case 'z' : /* Copy Compressed Data */
392
395
393
396
/*
394
397
* If we see Copy Data, just silently drop it. This would
@@ -1533,7 +1536,7 @@ getReadyForQuery(PGconn *conn)
1533
1536
* message available, -1 if end of copy, -2 if error.
1534
1537
*/
1535
1538
static int
1536
- getCopyDataMessage (PGconn * conn )
1539
+ getCopyDataMessage (PGconn * conn , char * kind )
1537
1540
{
1538
1541
char id ;
1539
1542
int msgLength ;
@@ -1584,6 +1587,7 @@ getCopyDataMessage(PGconn *conn)
1584
1587
* completeness.) Otherwise, if it's anything except Copy Data,
1585
1588
* report end-of-copy.
1586
1589
*/
1590
+ * kind = id ;
1587
1591
switch (id )
1588
1592
{
1589
1593
case 'A' : /* NOTIFY */
@@ -1599,6 +1603,7 @@ getCopyDataMessage(PGconn *conn)
1599
1603
return 0 ;
1600
1604
break ;
1601
1605
case 'd' : /* Copy Data, pass it back to caller */
1606
+ case 'z' : /* Copy Compressed Data, pass it back to caller */
1602
1607
return msgLength ;
1603
1608
case 'c' :
1604
1609
@@ -1641,6 +1646,7 @@ int
1641
1646
pqGetCopyData3 (PGconn * conn , char * * buffer , int async )
1642
1647
{
1643
1648
int msgLength ;
1649
+ char id ;
1644
1650
1645
1651
for (;;)
1646
1652
{
@@ -1649,7 +1655,7 @@ pqGetCopyData3(PGconn *conn, char **buffer, int async)
1649
1655
* callers, we keep returning 0 until the next message is fully
1650
1656
* available, even if it is not Copy Data.
1651
1657
*/
1652
- msgLength = getCopyDataMessage (conn );
1658
+ msgLength = getCopyDataMessage (conn , & id );
1653
1659
if (msgLength < 0 )
1654
1660
return msgLength ; /* end-of-copy or error */
1655
1661
if (msgLength == 0 )
@@ -1671,20 +1677,55 @@ pqGetCopyData3(PGconn *conn, char **buffer, int async)
1671
1677
msgLength -= 4 ;
1672
1678
if (msgLength > 0 )
1673
1679
{
1674
- * buffer = (char * ) malloc (msgLength + 1 );
1675
- if (* buffer == NULL )
1676
- {
1677
- printfPQExpBuffer (& conn -> errorMessage ,
1678
- libpq_gettext ("out of memory\n" ));
1679
- return -2 ;
1680
+ if (id == 'z' ) { /* compressed data */
1681
+ int zip_len = msgLength -= 4 ;
1682
+ int raw_len ;
1683
+ int len ;
1684
+
1685
+ Assert (zip_len > 0 );
1686
+
1687
+ if (pqGetInt (& raw_len , 4 , conn ))
1688
+ return -2 ;
1689
+
1690
+ * buffer = (char * ) malloc (raw_len + 1 );
1691
+ if (* buffer == NULL )
1692
+ {
1693
+ printfPQExpBuffer (& conn -> errorMessage ,
1694
+ libpq_gettext ("out of memory\n" ));
1695
+ return -2 ;
1696
+ }
1697
+ len = pglz_decompress (& conn -> inBuffer [conn -> inCursor ], zip_len , * buffer , raw_len );
1698
+ if (len != raw_len )
1699
+ {
1700
+ printfPQExpBuffer (& conn -> errorMessage ,
1701
+ libpq_gettext ("decompress error\n" ));
1702
+ return -2 ;
1703
+ }
1704
+ (* buffer )[raw_len ] = '\0' ; /* Add terminating null */
1705
+
1706
+
1707
+ /* Mark message consumed */
1708
+ conn -> inStart = conn -> inCursor + msgLength ;
1709
+
1710
+ return raw_len ;
1680
1711
}
1681
- memcpy (* buffer , & conn -> inBuffer [conn -> inCursor ], msgLength );
1682
- (* buffer )[msgLength ] = '\0' ; /* Add terminating null */
1712
+ else
1713
+ {
1714
+ * buffer = (char * ) malloc (msgLength + 1 );
1715
+ if (* buffer == NULL )
1716
+ {
1717
+ printfPQExpBuffer (& conn -> errorMessage ,
1718
+ libpq_gettext ("out of memory\n" ));
1719
+ return -2 ;
1720
+ }
1721
+ memcpy (* buffer , & conn -> inBuffer [conn -> inCursor ], msgLength );
1722
+ (* buffer )[msgLength ] = '\0' ; /* Add terminating null */
1683
1723
1684
- /* Mark message consumed */
1685
- conn -> inStart = conn -> inCursor + msgLength ;
1724
+ /* Mark message consumed */
1725
+ conn -> inStart = conn -> inCursor + msgLength ;
1686
1726
1687
- return msgLength ;
1727
+ return msgLength ;
1728
+ }
1688
1729
}
1689
1730
1690
1731
/* Empty, so drop it and loop around for another */
@@ -1754,6 +1795,7 @@ pqGetlineAsync3(PGconn *conn, char *buffer, int bufsize)
1754
1795
{
1755
1796
int msgLength ;
1756
1797
int avail ;
1798
+ char id ;
1757
1799
1758
1800
if (conn -> asyncStatus != PGASYNC_COPY_OUT
1759
1801
&& conn -> asyncStatus != PGASYNC_COPY_BOTH )
@@ -1765,7 +1807,7 @@ pqGetlineAsync3(PGconn *conn, char *buffer, int bufsize)
1765
1807
* even if it is not Copy Data. This should keep PQendcopy from blocking.
1766
1808
* (Note: unlike pqGetCopyData3, we do not change asyncStatus here.)
1767
1809
*/
1768
- msgLength = getCopyDataMessage (conn );
1810
+ msgLength = getCopyDataMessage (conn , & id );
1769
1811
if (msgLength < 0 )
1770
1812
return -1 ; /* end-of-copy or error */
1771
1813
if (msgLength == 0 )
0 commit comments