Skip to content

Commit e28ed2c

Browse files
authored
Fixed issue of incorrect splitting of response buffer into multiple packets for PLP Data (#3830)
Currently, in Babelfish for large response of nvarchar(max) type while splitting the response buffer into multiple packets the last PLP chunk is getting splitting directly and the next packet starts with rest of the part of PLP chunk. Instead if the last PLP chunk size cannot be accommodated into available buffer, the PLP chunk size should have been reduced to available buffer and next packet should start with new PLP chunk. This PR will fix this issue. Task: BABEL-5875 Signed-off-by: Rohit Bhagat <rohitbgt@amazon.com>
1 parent ab6bb4d commit e28ed2c

File tree

5 files changed

+1120
-0
lines changed

5 files changed

+1120
-0
lines changed

contrib/babelfishpg_tds/src/backend/tds/tdscomm.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,31 @@ static void SocketSetNonblocking(bool nonblocking);
5858
static int InternalFlush(bool);
5959
static void TdsConsumedBytes(int bytes);
6060

61+
/* --------------------------------
62+
* GetAvailableBufferSize - returns the available buffer size
63+
* --------------------------------
64+
*/
65+
size_t
66+
GetAvailableBufferSize()
67+
{
68+
return TdsBufferSize - TdsSendCur;
69+
}
70+
71+
/* --------------------------------
72+
* FlushBuffer - Flushes existing buffer with socket set as non-blocking
73+
*
74+
* returns 0 if OK, EOF if trouble
75+
* --------------------------------
76+
*/
77+
int
78+
FlushBuffer()
79+
{
80+
SocketSetNonblocking(false);
81+
if (InternalFlush(false))
82+
return EOF;
83+
return 0;
84+
}
85+
6186
/* Inline functions */
6287

6388
/* --------------------------------

contrib/babelfishpg_tds/src/backend/tds/tdstypeio.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2810,18 +2810,51 @@ TdsSendPlpDataHelper(char *data, int len)
28102810
uint32_t plpTerminator = PLP_TERMINATOR;
28112811
uint64_t tempOffset = 0;
28122812
uint32_t plpChunckLen = PLP_CHUNCK_LEN;
2813+
size_t availableBufferSpace = 0;
28132814

2815+
TdsErrorContext->err_text = "TdsSendPlpDataHelper - write PLP Data to the buffer";
2816+
TDS_DEBUG(TDS_DEBUG2, "PLP Data length = %d", len);
28142817
if ((rc = TdsPutInt64LE(len)) == 0)
28152818
{
28162819
while (true)
28172820
{
2821+
plpChunckLen = PLP_CHUNCK_LEN;
2822+
28182823
if (plpChunckLen > (len - tempOffset))
28192824
plpChunckLen = (len - tempOffset);
28202825

28212826
/* Either data is "0" or no more data to send */
28222827
if (plpChunckLen == 0)
28232828
break;
2829+
2830+
availableBufferSpace = GetAvailableBufferSize();
2831+
/*
2832+
* If PLP CHUNK block cannot be stored in available buffer,
2833+
* then set PLP CHUNK LEN to size of available buffer.
2834+
*
2835+
* Here plpChunckLen + sizeof(uint32_t) represents the size of chunk data
2836+
* and its length(i.e. size of uint32_t). This check will make sure that
2837+
* each PLP CHUNK and its length will remain in same packet.
2838+
*/
2839+
if ((plpChunckLen + sizeof(uint32_t)) > availableBufferSpace)
2840+
{
2841+
/*
2842+
* If available buffer size cannot accomodate smallest chunk i.e. of size 1 byte
2843+
* then flush the buffer and try again, else set PLP CHUNK LEN to size of available buffer.
2844+
*/
2845+
if (availableBufferSpace < (1 + sizeof(uint32_t)))
2846+
{
2847+
rc = FlushBuffer();
2848+
if (rc != 0)
2849+
return rc;
2850+
2851+
continue;
2852+
}
2853+
else
2854+
plpChunckLen = availableBufferSpace - sizeof(uint32_t);
2855+
}
28242856

2857+
TDS_DEBUG(TDS_DEBUG2, "PLP CHUNK length = %u, Available Buffer Size = %zu", plpChunckLen, availableBufferSpace);
28252858
/* need testing for "0" len */
28262859
if ((rc = TdsPutUInt32LE(plpChunckLen)) == 0)
28272860
{

contrib/babelfishpg_tds/src/include/tds_int.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,8 @@ extern uint32_t GetClientTDSVersion(void);
306306
extern char *get_tds_login_domainname(void);
307307
extern void TdsSetDbContext(void);
308308
extern void TdsResetLoginFlags(void);
309+
extern size_t GetAvailableBufferSize(void);
310+
extern int FlushBuffer(void);
309311

310312
/* Functions in backend/tds/tdsprotocol.c */
311313
extern int TdsSocketBackend(void);

0 commit comments

Comments
 (0)