Skip to content

Commit 701568c

Browse files
authored
Changes to support parameterized queries (#3)
* Changes to support parameterized queries * WIP Support for pg-protocol output * Buffer output * Flush output buffer on each message
1 parent 3443047 commit 701568c

File tree

2 files changed

+124
-13
lines changed

2 files changed

+124
-13
lines changed

src/backend/libpq/pqcomm.c

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@
8383
#include "utils/guc.h"
8484
#include "utils/memutils.h"
8585

86+
#ifdef EMSCRIPTEN
87+
#include <emscripten.h>
88+
#endif
89+
8690
/*
8791
* Cope with the various platform-specific ways to spell TCP keepalive socket
8892
* options. This doesn't cover Windows, which as usual does its own thing.
@@ -149,11 +153,28 @@ static void socket_putmessage_noblock(char msgtype, const char *s, size_t len);
149153
static int internal_putbytes(const char *s, size_t len);
150154
static int internal_flush(void);
151155

156+
static void emscripten_comm_reset(void);
157+
static int emscripten_flush(void);
158+
static int emscripten_flush_if_writable(void);
159+
static bool emscripten_is_send_pending(void);
160+
static int emscripten_putmessage(char msgtype, const char *s, size_t len);
161+
static void emscripten_putmessage_noblock(char msgtype, const char *s, size_t len);
162+
152163
#ifdef HAVE_UNIX_SOCKETS
153164
static int Lock_AF_UNIX(const char *unixSocketDir, const char *unixSocketPath);
154165
static int Setup_AF_UNIX(const char *sock_path);
155166
#endif /* HAVE_UNIX_SOCKETS */
156167

168+
#ifdef EMSCRIPTEN
169+
static const PQcommMethods PqCommSocketMethods = {
170+
emscripten_comm_reset,
171+
emscripten_flush,
172+
emscripten_flush_if_writable,
173+
emscripten_is_send_pending,
174+
emscripten_putmessage,
175+
emscripten_putmessage_noblock
176+
};
177+
#else
157178
static const PQcommMethods PqCommSocketMethods = {
158179
socket_comm_reset,
159180
socket_flush,
@@ -162,12 +183,97 @@ static const PQcommMethods PqCommSocketMethods = {
162183
socket_putmessage,
163184
socket_putmessage_noblock
164185
};
186+
#endif
165187

166188
const PQcommMethods *PqCommMethods = &PqCommSocketMethods;
167189

168190
WaitEventSet *FeBeWaitSet;
169191

170192

193+
/* --------------------------------
194+
* Emscripten implementation
195+
* --------------------------------
196+
*/
197+
198+
static StringInfoData emscripten_buffer;
199+
static bool emscripten_buffer_is_initialized = false;
200+
static bool emscripten_buffer_busy = false;
201+
202+
#ifdef EMSCRIPTEN
203+
EM_JS(void, emscripten_dispatch_result, (char *res, int len), {
204+
// Dispatch the result to JS land
205+
if (!Module.eventTarget) return;
206+
var heapBytes = new Uint8Array(Module.HEAPU8.buffer, res, len);
207+
var resultBytes = new Uint8Array(heapBytes);
208+
Module.eventTarget.dispatchEvent(new Module.Event("result", {
209+
detail: resultBytes
210+
}));
211+
});
212+
#endif
213+
214+
static void emscripten_init_buffer(void) {
215+
if (!emscripten_buffer_is_initialized) {
216+
initStringInfo(&emscripten_buffer);
217+
emscripten_buffer_is_initialized = true;
218+
}
219+
}
220+
221+
static void emscripten_comm_reset(void) {
222+
if (emscripten_buffer_is_initialized) {
223+
resetStringInfo(&emscripten_buffer);
224+
} else {
225+
emscripten_init_buffer();
226+
}
227+
}
228+
229+
static int emscripten_flush(void) {
230+
if (emscripten_buffer.len > 0) {
231+
emscripten_dispatch_result(emscripten_buffer.data, emscripten_buffer.len);
232+
resetStringInfo(&emscripten_buffer);
233+
}
234+
return 0;
235+
}
236+
237+
static int emscripten_flush_if_writable(void) {
238+
return emscripten_flush();
239+
return 0;
240+
}
241+
242+
static bool emscripten_is_send_pending(void) {
243+
return emscripten_buffer.len > 0;
244+
}
245+
246+
static int emscripten_putmessage(char msgtype, const char *s, size_t len) {
247+
if (emscripten_buffer_busy)
248+
return 0;
249+
emscripten_buffer_busy = true;
250+
251+
emscripten_init_buffer();
252+
253+
uint32 n32;
254+
Assert(msgtype != 0);
255+
256+
appendStringInfoChar(&emscripten_buffer, msgtype);
257+
n32 = pg_hton32((uint32) (len + 4));
258+
appendBinaryStringInfo(&emscripten_buffer, (char *) &n32, 4);
259+
appendBinaryStringInfo(&emscripten_buffer, s, len);
260+
261+
emscripten_buffer_busy = false;
262+
263+
// Flush buffer on every message
264+
emscripten_flush();
265+
266+
return 0;
267+
268+
fail:
269+
emscripten_buffer_busy = false;
270+
return EOF;
271+
}
272+
273+
static void emscripten_putmessage_noblock(char msgtype, const char *s, size_t len) {
274+
emscripten_putmessage(msgtype, s, len);
275+
}
276+
171277
/* --------------------------------
172278
* pq_init - initialize libpq at backend startup
173279
* --------------------------------

src/backend/tcop/postgres.c

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@
9393
const char *debug_query_string; /* client-supplied query string */
9494

9595
/* Note: whereToSendOutput is initialized for the bootstrap/standalone case */
96-
CommandDest whereToSendOutput = DestDebugJson;
96+
CommandDest whereToSendOutput = DestRemote;
9797

9898
/* flag for logging end of session */
9999
bool Log_disconnections = false;
@@ -351,31 +351,36 @@ interactive_getc(void)
351351
#ifdef EMSCRIPTEN
352352
EM_ASYNC_JS(char *, await_query, (), {
353353
// Await a query from JS land
354-
var event = new Module.Event("waiting");
355-
Module.eventTarget.dispatchEvent(event);
354+
Module.eventTarget.dispatchEvent(new Module.Event("waiting"));
356355
var query = await new Promise((resolve, reject) => {
357356
Module.eventTarget.addEventListener("query", (e) => {
358357
resolve(e.detail);
359358
}, {once: true});
360359
});
361-
var cstring_ptr = allocateUTF8(query);
362-
return cstring_ptr;
360+
// `query` is a Uint8Array containing the query in pg wire format
361+
var bytes = query.length;
362+
var ptr = _malloc(bytes);
363+
Module.HEAPU8.set(query, ptr);
364+
return ptr;
363365
});
364366
#endif
365367

366368
static int
367369
EmscriptenBackend(StringInfo inBuf)
368370
{
369371
char *query = await_query();
370-
char qtype = *query; // First character is qtype
371-
int qlen = strlen(query);
372+
char qtype = *query; // First byte is qtype
373+
374+
int32 msgLen = *((int32 *)(query + 1)); // Next 4 bytes are message length
375+
msgLen = pg_ntoh32(msgLen);
376+
int dataLen = msgLen - 4; // The rest of the message is the data
372377

373378
resetStringInfo(inBuf);
374-
if (qlen > 1)
375-
{
376-
appendBinaryStringInfoNT(inBuf, query + 1, qlen - 1);
377-
appendStringInfoChar(inBuf, (char) '\0');
378-
}
379+
if (dataLen > 0)
380+
{
381+
// Append the data to the buffer
382+
appendBinaryStringInfo(inBuf, query + 5, dataLen);
383+
}
379384

380385
free(query);
381386

@@ -524,7 +529,7 @@ ReadCommand(StringInfo inBuf)
524529
int result;
525530

526531
if (whereToSendOutput == DestRemote)
527-
result = SocketBackend(inBuf);
532+
result = EmscriptenBackend(inBuf);
528533
else if (whereToSendOutput == DestDebugJson)
529534
result = EmscriptenBackend(inBuf);
530535
else

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy