Lonely Patch Seeks Long-Term Commitment to Codebase
Hi,
I sent a patch to this list earlier this month to improve the speed of
PGunescapeBytea(). IMHO it is handicapped as it can take over a minute
to process a large amount of data, e.g. a 500Kb JPEG.
The attached patch replaces the sscanf function that causes the delay,
the code was borrowed from the PostgreSQL Python interface with
permission from the author.
Please could I have some feedback on whether the patch is likely to be
committed? Has it been rejected? Is it stuck on someone's TODO list? Was
the code unsuitable? Have I neglected some procedure, etc?
Best regards,
Ben Lamb.
Attachments:
fe-exec.c.patchtext/plain; name=fe-exec.c.patchDownload+42-75
I think Bruce is still working through his backlog of patches. I know I'm
waiting for my pg_autovacuum patch to be applied which was submitted on May
7th.
Just give him some time, he's been working hard on the win32 port, a worthy
and difficult task IMHO.
Matthew
----- Original Message -----
From: "Ben Lamb" <pgsql-patches@zurgy.org>
To: <pgsql-patches@postgresql.org>
Sent: Wednesday, May 28, 2003 3:26 PM
Subject: [PATCHES] Lonely Patch Seeks Long-Term Commitment to Codebase
Hi,
I sent a patch to this list earlier this month to improve the speed of
PGunescapeBytea(). IMHO it is handicapped as it can take over a minute
to process a large amount of data, e.g. a 500Kb JPEG.The attached patch replaces the sscanf function that causes the delay,
the code was borrowed from the PostgreSQL Python interface with
permission from the author.Please could I have some feedback on whether the patch is likely to be
committed? Has it been rejected? Is it stuck on someone's TODO list? Was
the code unsuitable? Have I neglected some procedure, etc?Best regards,
Ben Lamb.
----------------------------------------------------------------------------
----
--- fe-exec.c Thu May 8 11:49:34 2003 +++ fe-exec.c.latest Thu May 8 11:45:17 2003 @@ -180,6 +180,8 @@ return result; }+#define VAL(CH) ((CH) - '0') + /* * PQunescapeBytea - converts the null terminated string representation * of a bytea, strtext, into binary, filling a buffer. It returns a @@ -187,101 +189,66 @@ * buffer in retbuflen. The pointer may subsequently be used as an * argument to the function free(3). It is the reverse of PQescapeBytea. * - * The following transformations are reversed: - * '\0' == ASCII 0 == \000 - * '\'' == ASCII 39 == \' - * '\\' == ASCII 92 == \\ + * The following transformations are made: + * \' == ASCII 39 == ' + * \\ == ASCII 92 == \ + * \ooo == a byte whose value = ooo (ooo is an octal number) + * \x == x (x is any character not matched by the above
transformations)
* - * States: - * 0 normal 0->1->2->3->4 - * 1 \ 1->5 - * 2 \0 1->6 - * 3 \00 - * 4 \000 - * 5 \' - * 6 \\ */ unsigned char * PQunescapeBytea(unsigned char *strtext, size_t *retbuflen) { - size_t buflen; - unsigned char *buffer, - *sp, - *bp; - unsigned int state = 0; + size_t strtextlen, buflen; + unsigned char *buffer, *tmpbuf; + int i, j, byte;- if (strtext == NULL) + if (strtext == NULL) { return NULL; - buflen = strlen(strtext); /* will shrink, also we discover if - * strtext */ - buffer = (unsigned char *) malloc(buflen); /* isn't NULL terminated */ + } + + strtextlen = strlen(strtext); /* will shrink, also we discover if + * strtext isn't NULL terminated */ + buffer = (unsigned char *)malloc(strtextlen); if (buffer == NULL) return NULL; - for (bp = buffer, sp = strtext; *sp != '\0'; bp++, sp++) + + for (i = j = buflen = 0; i < strtextlen;) { - switch (state) + switch (strtext[i]) { - case 0: - if (*sp == '\\') - state = 1; - *bp = *sp; - break; - case 1: - if (*sp == '\'') /* state=5 */ - { /* replace \' with 39 */ - bp--; - *bp = '\''; - buflen--; - state = 0; - } - else if (*sp == '\\') /* state=6 */ - { /* replace \\ with 92 */ - bp--; - *bp = '\\'; - buflen--; - state = 0; - } + case '\\': + i++; + if (strtext[i] == '\\') + buffer[j++] = strtext[i++]; else { - if (isdigit(*sp)) - state = 2; - else - state = 0; - *bp = *sp; + if ((isdigit(strtext[i])) && + (isdigit(strtext[i+1])) && + (isdigit(strtext[i+2]))) + { + byte = VAL(strtext[i++]); + byte = (byte << 3) + VAL(strtext[i++]); + buffer[j++] = (byte << 3) + VAL(strtext[i++]); + } } break; - case 2: - if (isdigit(*sp)) - state = 3; - else - state = 0; - *bp = *sp; - break; - case 3: - if (isdigit(*sp)) /* state=4 */ - { - int v;- bp -= 3; - sscanf(sp - 2, "%03o", &v); - *bp = v; - buflen -= 3; - state = 0; - } - else - { - *bp = *sp; - state = 0; - } - break; + default: + buffer[j++] = strtext[i++]; } } - buffer = realloc(buffer, buflen); - if (buffer == NULL) - return NULL; + buflen = j; /* buflen is the length of the unquoted data */ + tmpbuf = realloc(buffer, buflen); + + if (!tmpbuf) + { + free(buffer); + return 0; + }*retbuflen = buflen; - return buffer; + return tmpbuf; }/* ----------------
----------------------------------------------------------------------------
----
Show quoted text
---------------------------(end of broadcast)---------------------------
TIP 2: you can get off all lists at once with the unregister command
(send "unregister YourEmailAddressHere" to majordomo@postgresql.org)
I think he said he was going to take a break of about a week to catch up on
patches, so I was waiting till that time was over before making a similar
query. I haven't seen a lot of "Thankyou, this patch has been applied"
messages, though.
cheers
andrew
----- Original Message -----
From: "Matthew T. O'Connor" <matthew@zeut.net>
To: "Ben Lamb" <pgsql-patches@zurgy.org>; <pgsql-patches@postgresql.org>
Sent: Wednesday, May 28, 2003 4:30 PM
Subject: Re: [PATCHES] Lonely Patch Seeks Long-Term Commitment to Codebase
I think Bruce is still working through his backlog of patches. I know I'm
waiting for my pg_autovacuum patch to be applied which was submitted on
May
7th.
Just give him some time, he's been working hard on the win32 port, a
worthy
and difficult task IMHO.
Matthew
----- Original Message -----
From: "Ben Lamb" <pgsql-patches@zurgy.org>
To: <pgsql-patches@postgresql.org>
Sent: Wednesday, May 28, 2003 3:26 PM
Subject: [PATCHES] Lonely Patch Seeks Long-Term Commitment to CodebaseHi,
I sent a patch to this list earlier this month to improve the speed of
PGunescapeBytea(). IMHO it is handicapped as it can take over a minute
to process a large amount of data, e.g. a 500Kb JPEG.The attached patch replaces the sscanf function that causes the delay,
the code was borrowed from the PostgreSQL Python interface with
permission from the author.Please could I have some feedback on whether the patch is likely to be
committed? Has it been rejected? Is it stuck on someone's TODO list? Was
the code unsuitable? Have I neglected some procedure, etc?Best regards,
Ben Lamb.
--------------------------------------------------------------------------
--
----
--- fe-exec.c Thu May 8 11:49:34 2003 +++ fe-exec.c.latest Thu May 8 11:45:17 2003 @@ -180,6 +180,8 @@ return result; }+#define VAL(CH) ((CH) - '0')
+
/*
* PQunescapeBytea - converts the null terminated string representation
* of a bytea, strtext, into binary, filling a buffer. It returns a
@@ -187,101 +189,66 @@
* buffer in retbuflen. The pointer may subsequently be used as an
* argument to the function free(3). It is the reverse of
PQescapeBytea.
* - * The following transformations are reversed: - * '\0' == ASCII 0 == \000 - * '\'' == ASCII 39 == \' - * '\\' == ASCII 92 == \\ + * The following transformations are made: + * \' == ASCII 39 == ' + * \\ == ASCII 92 == \ + * \ooo == a byte whose value = ooo (ooo is an octal number) + * \x == x (x is any character not matched by the abovetransformations)
* - * States: - * 0 normal 0->1->2->3->4 - * 1 \ 1->5 - * 2 \0 1->6 - * 3 \00 - * 4 \000 - * 5 \' - * 6 \\ */ unsigned char * PQunescapeBytea(unsigned char *strtext, size_t *retbuflen) { - size_t buflen; - unsigned char *buffer, - *sp, - *bp; - unsigned int state = 0; + size_t strtextlen, buflen; + unsigned char *buffer, *tmpbuf; + int i, j, byte;- if (strtext == NULL) + if (strtext == NULL) { return NULL; - buflen = strlen(strtext); /* will shrink, also we discover if - * strtext */ - buffer = (unsigned char *) malloc(buflen); /* isn't NULL terminated */ + } + + strtextlen = strlen(strtext); /* will shrink, also we discover if + * strtext isn't NULL terminated */ + buffer = (unsigned char *)malloc(strtextlen); if (buffer == NULL) return NULL; - for (bp = buffer, sp = strtext; *sp != '\0'; bp++, sp++) + + for (i = j = buflen = 0; i < strtextlen;) { - switch (state) + switch (strtext[i]) { - case 0: - if (*sp == '\\') - state = 1; - *bp = *sp; - break; - case 1: - if (*sp == '\'') /* state=5 */ - { /* replace \' with 39 */ - bp--; - *bp = '\''; - buflen--; - state = 0; - } - else if (*sp == '\\') /* state=6 */ - { /* replace \\ with 92 */ - bp--; - *bp = '\\'; - buflen--; - state = 0; - } + case '\\': + i++; + if (strtext[i] == '\\') + buffer[j++] = strtext[i++]; else { - if (isdigit(*sp)) - state = 2; - else - state = 0; - *bp = *sp; + if ((isdigit(strtext[i])) && + (isdigit(strtext[i+1])) && + (isdigit(strtext[i+2]))) + { + byte = VAL(strtext[i++]); + byte = (byte << 3) + VAL(strtext[i++]); + buffer[j++] = (byte << 3) + VAL(strtext[i++]); + } } break; - case 2: - if (isdigit(*sp)) - state = 3; - else - state = 0; - *bp = *sp; - break; - case 3: - if (isdigit(*sp)) /* state=4 */ - { - int v;- bp -= 3; - sscanf(sp - 2, "%03o", &v); - *bp = v; - buflen -= 3; - state = 0; - } - else - { - *bp = *sp; - state = 0; - } - break; + default: + buffer[j++] = strtext[i++]; } } - buffer = realloc(buffer, buflen); - if (buffer == NULL) - return NULL; + buflen = j; /* buflen is the length of the unquoted data */ + tmpbuf = realloc(buffer, buflen); + + if (!tmpbuf) + { + free(buffer); + return 0; + }*retbuflen = buflen; - return buffer; + return tmpbuf; }/* ----------------
--------------------------------------------------------------------------
--
Show quoted text
----
---------------------------(end of broadcast)---------------------------
TIP 2: you can get off all lists at once with the unregister command
(send "unregister YourEmailAddressHere" to majordomo@postgresql.org)---------------------------(end of broadcast)---------------------------
TIP 2: you can get off all lists at once with the unregister command
(send "unregister YourEmailAddressHere" to majordomo@postgresql.org)
On Wed, May 28, 2003 at 04:30:39PM -0400, Matthew T. O'Connor wrote:
I think Bruce is still working through his backlog of patches. I know I'm
waiting for my pg_autovacuum patch to be applied which was submitted on May
7th.
Apologies, I'm a newbie and wasn't sure what to expect when I sent the patch to the list.
Thanks,
Ben.
From: "Ben Lamb" <pgsql-patches@zurgy.org>
Apologies, I'm a newbie and wasn't sure what to expect when I sent the
patch to the list.
No problem, keep sending patches :-)
Matthew T. O'Connor wrote:
From: "Ben Lamb" <pgsql-patches@zurgy.org>
Apologies, I'm a newbie and wasn't sure what to expect when I sent the
patch to the list.
No problem, keep sending patches :-)
I am working through my email. I am in early April now, so I have a few
weeks to go. These are the emails/patches that need special attention.
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Ben, this patch is slightly different from your previous patch. Is this
the better version?
---------------------------------------------------------------------------
Ben Lamb wrote:
Hi,
I sent a patch to this list earlier this month to improve the speed of
PGunescapeBytea(). IMHO it is handicapped as it can take over a minute
to process a large amount of data, e.g. a 500Kb JPEG.The attached patch replaces the sscanf function that causes the delay,
the code was borrowed from the PostgreSQL Python interface with
permission from the author.Please could I have some feedback on whether the patch is likely to be
committed? Has it been rejected? Is it stuck on someone's TODO list? Was
the code unsuitable? Have I neglected some procedure, etc?Best regards,
Ben Lamb.
--- fe-exec.c Thu May 8 11:49:34 2003 +++ fe-exec.c.latest Thu May 8 11:45:17 2003 @@ -180,6 +180,8 @@ return result; }+#define VAL(CH) ((CH) - '0') + /* * PQunescapeBytea - converts the null terminated string representation * of a bytea, strtext, into binary, filling a buffer. It returns a @@ -187,101 +189,66 @@ * buffer in retbuflen. The pointer may subsequently be used as an * argument to the function free(3). It is the reverse of PQescapeBytea. * - * The following transformations are reversed: - * '\0' == ASCII 0 == \000 - * '\'' == ASCII 39 == \' - * '\\' == ASCII 92 == \\ + * The following transformations are made: + * \' == ASCII 39 == ' + * \\ == ASCII 92 == \ + * \ooo == a byte whose value = ooo (ooo is an octal number) + * \x == x (x is any character not matched by the above transformations) * - * States: - * 0 normal 0->1->2->3->4 - * 1 \ 1->5 - * 2 \0 1->6 - * 3 \00 - * 4 \000 - * 5 \' - * 6 \\ */ unsigned char * PQunescapeBytea(unsigned char *strtext, size_t *retbuflen) { - size_t buflen; - unsigned char *buffer, - *sp, - *bp; - unsigned int state = 0; + size_t strtextlen, buflen; + unsigned char *buffer, *tmpbuf; + int i, j, byte;- if (strtext == NULL) + if (strtext == NULL) { return NULL; - buflen = strlen(strtext); /* will shrink, also we discover if - * strtext */ - buffer = (unsigned char *) malloc(buflen); /* isn't NULL terminated */ + } + + strtextlen = strlen(strtext); /* will shrink, also we discover if + * strtext isn't NULL terminated */ + buffer = (unsigned char *)malloc(strtextlen); if (buffer == NULL) return NULL; - for (bp = buffer, sp = strtext; *sp != '\0'; bp++, sp++) + + for (i = j = buflen = 0; i < strtextlen;) { - switch (state) + switch (strtext[i]) { - case 0: - if (*sp == '\\') - state = 1; - *bp = *sp; - break; - case 1: - if (*sp == '\'') /* state=5 */ - { /* replace \' with 39 */ - bp--; - *bp = '\''; - buflen--; - state = 0; - } - else if (*sp == '\\') /* state=6 */ - { /* replace \\ with 92 */ - bp--; - *bp = '\\'; - buflen--; - state = 0; - } + case '\\': + i++; + if (strtext[i] == '\\') + buffer[j++] = strtext[i++]; else { - if (isdigit(*sp)) - state = 2; - else - state = 0; - *bp = *sp; + if ((isdigit(strtext[i])) && + (isdigit(strtext[i+1])) && + (isdigit(strtext[i+2]))) + { + byte = VAL(strtext[i++]); + byte = (byte << 3) + VAL(strtext[i++]); + buffer[j++] = (byte << 3) + VAL(strtext[i++]); + } } break; - case 2: - if (isdigit(*sp)) - state = 3; - else - state = 0; - *bp = *sp; - break; - case 3: - if (isdigit(*sp)) /* state=4 */ - { - int v;- bp -= 3; - sscanf(sp - 2, "%03o", &v); - *bp = v; - buflen -= 3; - state = 0; - } - else - { - *bp = *sp; - state = 0; - } - break; + default: + buffer[j++] = strtext[i++]; } } - buffer = realloc(buffer, buflen); - if (buffer == NULL) - return NULL; + buflen = j; /* buflen is the length of the unquoted data */ + tmpbuf = realloc(buffer, buflen); + + if (!tmpbuf) + { + free(buffer); + return 0; + }*retbuflen = buflen; - return buffer; + return tmpbuf; }/* ----------------
---------------------------(end of broadcast)---------------------------
TIP 2: you can get off all lists at once with the unregister command
(send "unregister YourEmailAddressHere" to majordomo@postgresql.org)
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Ben, never mind. I see this is now identical to the newest version of
the patch you posted. Sorry.
---------------------------------------------------------------------------
Ben Lamb wrote:
Hi,
I sent a patch to this list earlier this month to improve the speed of
PGunescapeBytea(). IMHO it is handicapped as it can take over a minute
to process a large amount of data, e.g. a 500Kb JPEG.The attached patch replaces the sscanf function that causes the delay,
the code was borrowed from the PostgreSQL Python interface with
permission from the author.Please could I have some feedback on whether the patch is likely to be
committed? Has it been rejected? Is it stuck on someone's TODO list? Was
the code unsuitable? Have I neglected some procedure, etc?Best regards,
Ben Lamb.
--- fe-exec.c Thu May 8 11:49:34 2003 +++ fe-exec.c.latest Thu May 8 11:45:17 2003 @@ -180,6 +180,8 @@ return result; }+#define VAL(CH) ((CH) - '0') + /* * PQunescapeBytea - converts the null terminated string representation * of a bytea, strtext, into binary, filling a buffer. It returns a @@ -187,101 +189,66 @@ * buffer in retbuflen. The pointer may subsequently be used as an * argument to the function free(3). It is the reverse of PQescapeBytea. * - * The following transformations are reversed: - * '\0' == ASCII 0 == \000 - * '\'' == ASCII 39 == \' - * '\\' == ASCII 92 == \\ + * The following transformations are made: + * \' == ASCII 39 == ' + * \\ == ASCII 92 == \ + * \ooo == a byte whose value = ooo (ooo is an octal number) + * \x == x (x is any character not matched by the above transformations) * - * States: - * 0 normal 0->1->2->3->4 - * 1 \ 1->5 - * 2 \0 1->6 - * 3 \00 - * 4 \000 - * 5 \' - * 6 \\ */ unsigned char * PQunescapeBytea(unsigned char *strtext, size_t *retbuflen) { - size_t buflen; - unsigned char *buffer, - *sp, - *bp; - unsigned int state = 0; + size_t strtextlen, buflen; + unsigned char *buffer, *tmpbuf; + int i, j, byte;- if (strtext == NULL) + if (strtext == NULL) { return NULL; - buflen = strlen(strtext); /* will shrink, also we discover if - * strtext */ - buffer = (unsigned char *) malloc(buflen); /* isn't NULL terminated */ + } + + strtextlen = strlen(strtext); /* will shrink, also we discover if + * strtext isn't NULL terminated */ + buffer = (unsigned char *)malloc(strtextlen); if (buffer == NULL) return NULL; - for (bp = buffer, sp = strtext; *sp != '\0'; bp++, sp++) + + for (i = j = buflen = 0; i < strtextlen;) { - switch (state) + switch (strtext[i]) { - case 0: - if (*sp == '\\') - state = 1; - *bp = *sp; - break; - case 1: - if (*sp == '\'') /* state=5 */ - { /* replace \' with 39 */ - bp--; - *bp = '\''; - buflen--; - state = 0; - } - else if (*sp == '\\') /* state=6 */ - { /* replace \\ with 92 */ - bp--; - *bp = '\\'; - buflen--; - state = 0; - } + case '\\': + i++; + if (strtext[i] == '\\') + buffer[j++] = strtext[i++]; else { - if (isdigit(*sp)) - state = 2; - else - state = 0; - *bp = *sp; + if ((isdigit(strtext[i])) && + (isdigit(strtext[i+1])) && + (isdigit(strtext[i+2]))) + { + byte = VAL(strtext[i++]); + byte = (byte << 3) + VAL(strtext[i++]); + buffer[j++] = (byte << 3) + VAL(strtext[i++]); + } } break; - case 2: - if (isdigit(*sp)) - state = 3; - else - state = 0; - *bp = *sp; - break; - case 3: - if (isdigit(*sp)) /* state=4 */ - { - int v;- bp -= 3; - sscanf(sp - 2, "%03o", &v); - *bp = v; - buflen -= 3; - state = 0; - } - else - { - *bp = *sp; - state = 0; - } - break; + default: + buffer[j++] = strtext[i++]; } } - buffer = realloc(buffer, buflen); - if (buffer == NULL) - return NULL; + buflen = j; /* buflen is the length of the unquoted data */ + tmpbuf = realloc(buffer, buflen); + + if (!tmpbuf) + { + free(buffer); + return 0; + }*retbuflen = buflen; - return buffer; + return tmpbuf; }/* ----------------
---------------------------(end of broadcast)---------------------------
TIP 2: you can get off all lists at once with the unregister command
(send "unregister YourEmailAddressHere" to majordomo@postgresql.org)
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073