Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit86eaf20

Browse files
committed
Hand code string to integer conversion for performance.
As benchmarks show, using libc's string-to-integer conversion ispretty slow. At least part of the reason for that is that strtol[l]have to be more generic than what largely is required inside pg.This patch considerably speeds up int2/int4 input (int8 already wasalready using hand-rolled code).Most of the existing pg_atoi callers have been converted. But as onerequires pg_atoi's custom delimiter functionality, and as it seemslikely that there's external pg_atoi users, it seems sensible to justkeep pg_atoi around.Author: Andres FreundReviewed-By: Robert HaasDiscussion:https://postgr.es/m/20171208214437.qgn6zdltyq5hmjpk@alap3.anarazel.de
1 parent3522d0e commit86eaf20

File tree

13 files changed

+176
-25
lines changed

13 files changed

+176
-25
lines changed

‎contrib/spi/refint.c‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ check_foreign_key(PG_FUNCTION_ARGS)
306306
/* internal error */
307307
elog(ERROR,"check_foreign_key: too short %d (< 5) list of arguments",nargs);
308308

309-
nrefs=pg_atoi(args[0],sizeof(int),0);
309+
nrefs=pg_strtoint32(args[0]);
310310
if (nrefs<1)
311311
/* internal error */
312312
elog(ERROR,"check_foreign_key: %d (< 1) number of references specified",nrefs);

‎doc/src/sgml/sources.sgml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -709,7 +709,7 @@ BETTER: could not open file %s (I/O failure)
709709
not helpful information. If the error text doesn't make as much sense
710710
without the function name, reword it.
711711
<programlisting>
712-
BAD:pg_atoi: error in "z": cannot parse "z"
712+
BAD:pg_strtoint32: error in "z": cannot parse "z"
713713
BETTER: invalid input syntax for integer: "z"
714714
</programlisting>
715715
</para>

‎src/backend/libpq/pqmq.c‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -286,10 +286,10 @@ pq_parse_errornotice(StringInfo msg, ErrorData *edata)
286286
edata->hint=pstrdup(value);
287287
break;
288288
casePG_DIAG_STATEMENT_POSITION:
289-
edata->cursorpos=pg_atoi(value,sizeof(int),'\0');
289+
edata->cursorpos=pg_strtoint32(value);
290290
break;
291291
casePG_DIAG_INTERNAL_POSITION:
292-
edata->internalpos=pg_atoi(value,sizeof(int),'\0');
292+
edata->internalpos=pg_strtoint32(value);
293293
break;
294294
casePG_DIAG_INTERNAL_QUERY:
295295
edata->internalquery=pstrdup(value);
@@ -316,7 +316,7 @@ pq_parse_errornotice(StringInfo msg, ErrorData *edata)
316316
edata->filename=pstrdup(value);
317317
break;
318318
casePG_DIAG_SOURCE_LINE:
319-
edata->lineno=pg_atoi(value,sizeof(int),'\0');
319+
edata->lineno=pg_strtoint32(value);
320320
break;
321321
casePG_DIAG_SOURCE_FUNCTION:
322322
edata->funcname=pstrdup(value);

‎src/backend/replication/libpqwalreceiver/libpqwalreceiver.c‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ libpqrcv_identify_system(WalReceiverConn *conn, TimeLineID *primary_tli,
345345
ntuples,nfields,3,1)));
346346
}
347347
primary_sysid=pstrdup(PQgetvalue(res,0,0));
348-
*primary_tli=pg_atoi(PQgetvalue(res,0,1),4,0);
348+
*primary_tli=pg_strtoint32(PQgetvalue(res,0,1));
349349
PQclear(res);
350350

351351
*server_version=PQserverVersion(conn->streamConn);
@@ -480,7 +480,7 @@ libpqrcv_endstreaming(WalReceiverConn *conn, TimeLineID *next_tli)
480480
if (PQnfields(res)<2||PQntuples(res)!=1)
481481
ereport(ERROR,
482482
(errmsg("unexpected result set after end-of-streaming")));
483-
*next_tli=pg_atoi(PQgetvalue(res,0,0),sizeof(uint32),0);
483+
*next_tli=pg_strtoint32(PQgetvalue(res,0,0));
484484
PQclear(res);
485485

486486
/* the result set should be followed by CommandComplete */

‎src/backend/tsearch/wparser_def.c‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2460,13 +2460,13 @@ prsd_headline(PG_FUNCTION_ARGS)
24602460
char*val=defGetString(defel);
24612461

24622462
if (pg_strcasecmp(defel->defname,"MaxWords")==0)
2463-
max_words=pg_atoi(val,sizeof(int32),0);
2463+
max_words=pg_strtoint32(val);
24642464
elseif (pg_strcasecmp(defel->defname,"MinWords")==0)
2465-
min_words=pg_atoi(val,sizeof(int32),0);
2465+
min_words=pg_strtoint32(val);
24662466
elseif (pg_strcasecmp(defel->defname,"ShortWord")==0)
2467-
shortword=pg_atoi(val,sizeof(int32),0);
2467+
shortword=pg_strtoint32(val);
24682468
elseif (pg_strcasecmp(defel->defname,"MaxFragments")==0)
2469-
max_fragments=pg_atoi(val,sizeof(int32),0);
2469+
max_fragments=pg_strtoint32(val);
24702470
elseif (pg_strcasecmp(defel->defname,"StartSel")==0)
24712471
prs->startsel=pstrdup(val);
24722472
elseif (pg_strcasecmp(defel->defname,"StopSel")==0)

‎src/backend/utils/adt/arrayutils.c‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,8 +226,7 @@ ArrayGetIntegerTypmods(ArrayType *arr, int *n)
226226
result= (int32*)palloc(*n*sizeof(int32));
227227

228228
for (i=0;i<*n;i++)
229-
result[i]=pg_atoi(DatumGetCString(elem_values[i]),
230-
sizeof(int32),'\0');
229+
result[i]=pg_strtoint32(DatumGetCString(elem_values[i]));
231230

232231
pfree(elem_values);
233232

‎src/backend/utils/adt/int.c‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ int2in(PG_FUNCTION_ARGS)
6060
{
6161
char*num=PG_GETARG_CSTRING(0);
6262

63-
PG_RETURN_INT16(pg_atoi(num,sizeof(int16),'\0'));
63+
PG_RETURN_INT16(pg_strtoint16(num));
6464
}
6565

6666
/*
@@ -265,7 +265,7 @@ int4in(PG_FUNCTION_ARGS)
265265
{
266266
char*num=PG_GETARG_CSTRING(0);
267267

268-
PG_RETURN_INT32(pg_atoi(num,sizeof(int32),'\0'));
268+
PG_RETURN_INT32(pg_strtoint32(num));
269269
}
270270

271271
/*

‎src/backend/utils/adt/int8.c‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ scanint8(const char *str, bool errorOK, int64 *result)
101101

102102
if (!neg)
103103
{
104+
/* could fail if input is most negative number */
104105
if (unlikely(tmp==PG_INT64_MIN))
105106
gotoout_of_range;
106107
tmp=-tmp;

‎src/backend/utils/adt/numutils.c‎

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include<limits.h>
1919
#include<ctype.h>
2020

21+
#include"common/int.h"
2122
#include"utils/builtins.h"
2223

2324
/*
@@ -108,6 +109,154 @@ pg_atoi(const char *s, int size, int c)
108109
return (int32)l;
109110
}
110111

112+
/*
113+
* Convert input string to a signed 16 bit integer.
114+
*
115+
* Allows any number of leading or trailing whitespace characters. Will throw
116+
* ereport() upon bad input format or overflow.
117+
*
118+
* NB: Accumulate input as a negative number, to deal with two's complement
119+
* representation of the most negative number, which can't be represented as a
120+
* positive number.
121+
*/
122+
int16
123+
pg_strtoint16(constchar*s)
124+
{
125+
constchar*ptr=s;
126+
int16tmp=0;
127+
boolneg= false;
128+
129+
/* skip leading spaces */
130+
while (likely(*ptr)&&isspace((unsignedchar)*ptr))
131+
ptr++;
132+
133+
/* handle sign */
134+
if (*ptr=='-')
135+
{
136+
ptr++;
137+
neg= true;
138+
}
139+
elseif (*ptr=='+')
140+
ptr++;
141+
142+
/* require at least one digit */
143+
if (unlikely(!isdigit((unsignedchar)*ptr)))
144+
gotoinvalid_syntax;
145+
146+
/* process digits */
147+
while (*ptr&&isdigit((unsignedchar)*ptr))
148+
{
149+
int8digit= (*ptr++-'0');
150+
151+
if (unlikely(pg_mul_s16_overflow(tmp,10,&tmp))||
152+
unlikely(pg_sub_s16_overflow(tmp,digit,&tmp)))
153+
gotoout_of_range;
154+
}
155+
156+
/* allow trailing whitespace, but not other trailing chars */
157+
while (*ptr!='\0'&&isspace((unsignedchar)*ptr))
158+
ptr++;
159+
160+
if (unlikely(*ptr!='\0'))
161+
gotoinvalid_syntax;
162+
163+
if (!neg)
164+
{
165+
/* could fail if input is most negative number */
166+
if (unlikely(tmp==PG_INT16_MIN))
167+
gotoout_of_range;
168+
tmp=-tmp;
169+
}
170+
171+
returntmp;
172+
173+
out_of_range:
174+
ereport(ERROR,
175+
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
176+
errmsg("value \"%s\" is out of range for type %s",
177+
s,"smallint")));
178+
179+
invalid_syntax:
180+
ereport(ERROR,
181+
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
182+
errmsg("invalid input syntax for type %s: \"%s\"",
183+
"smallint",s)));
184+
}
185+
186+
/*
187+
* Convert input string to a signed 32 bit integer.
188+
*
189+
* Allows any number of leading or trailing whitespace characters. Will throw
190+
* ereport() upon bad input format or overflow.
191+
*
192+
* NB: Accumulate input as a negative number, to deal with two's complement
193+
* representation of the most negative number, which can't be represented as a
194+
* positive number.
195+
*/
196+
int32
197+
pg_strtoint32(constchar*s)
198+
{
199+
constchar*ptr=s;
200+
int32tmp=0;
201+
boolneg= false;
202+
203+
/* skip leading spaces */
204+
while (likely(*ptr)&&isspace((unsignedchar)*ptr))
205+
ptr++;
206+
207+
/* handle sign */
208+
if (*ptr=='-')
209+
{
210+
ptr++;
211+
neg= true;
212+
}
213+
elseif (*ptr=='+')
214+
ptr++;
215+
216+
/* require at least one digit */
217+
if (unlikely(!isdigit((unsignedchar)*ptr)))
218+
gotoinvalid_syntax;
219+
220+
/* process digits */
221+
while (*ptr&&isdigit((unsignedchar)*ptr))
222+
{
223+
int8digit= (*ptr++-'0');
224+
225+
if (unlikely(pg_mul_s32_overflow(tmp,10,&tmp))||
226+
unlikely(pg_sub_s32_overflow(tmp,digit,&tmp)))
227+
gotoout_of_range;
228+
}
229+
230+
/* allow trailing whitespace, but not other trailing chars */
231+
while (*ptr!='\0'&&isspace((unsignedchar)*ptr))
232+
ptr++;
233+
234+
if (unlikely(*ptr!='\0'))
235+
gotoinvalid_syntax;
236+
237+
if (!neg)
238+
{
239+
/* could fail if input is most negative number */
240+
if (unlikely(tmp==PG_INT32_MIN))
241+
gotoout_of_range;
242+
tmp=-tmp;
243+
}
244+
245+
returntmp;
246+
247+
out_of_range:
248+
ereport(ERROR,
249+
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
250+
errmsg("value \"%s\" is out of range for type %s",
251+
s,"integer")));
252+
253+
invalid_syntax:
254+
ereport(ERROR,
255+
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
256+
errmsg("invalid input syntax for type %s: \"%s\"",
257+
"integer",s)));
258+
}
259+
111260
/*
112261
* pg_itoa: converts a signed 16-bit integer to its string representation
113262
*

‎src/backend/utils/adt/varlena.c‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5155,8 +5155,8 @@ text_format(PG_FUNCTION_ARGS)
51555155

51565156
str=OutputFunctionCall(&typoutputinfo_width,value);
51575157

5158-
/*pg_atoi will complain about bad data or overflow */
5159-
width=pg_atoi(str,sizeof(int),'\0');
5158+
/*pg_strtoint32 will complain about bad data or overflow */
5159+
width=pg_strtoint32(str);
51605160

51615161
pfree(str);
51625162
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp