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
}

‎src/include/utils/builtins.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ extern intnamestrcmp(Name name, const char *str);
4343

4444
/* numutils.c */
4545
externint32pg_atoi(constchar*s,intsize,intc);
46+
externint16pg_strtoint16(constchar*s);
47+
externint32pg_strtoint32(constchar*s);
4648
externvoidpg_itoa(int16i,char*a);
4749
externvoidpg_ltoa(int32l,char*a);
4850
externvoidpg_lltoa(int64ll,char*a);

‎src/test/regress/expected/int2.out

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ INSERT INTO INT2_TBL(f1) VALUES ('0 ');
66
INSERT INTO INT2_TBL(f1) VALUES (' 1234 ');
77
INSERT INTO INT2_TBL(f1) VALUES (' -1234');
88
INSERT INTO INT2_TBL(f1) VALUES ('34.5');
9-
ERROR: invalid input syntax for typeinteger: "34.5"
9+
ERROR: invalid input syntax for typesmallint: "34.5"
1010
LINE 1: INSERT INTO INT2_TBL(f1) VALUES ('34.5');
1111
^
1212
-- largest and smallest values
@@ -18,27 +18,27 @@ ERROR: value "100000" is out of range for type smallint
1818
LINE 1: INSERT INTO INT2_TBL(f1) VALUES ('100000');
1919
^
2020
INSERT INTO INT2_TBL(f1) VALUES ('asdf');
21-
ERROR: invalid input syntax for typeinteger: "asdf"
21+
ERROR: invalid input syntax for typesmallint: "asdf"
2222
LINE 1: INSERT INTO INT2_TBL(f1) VALUES ('asdf');
2323
^
2424
INSERT INTO INT2_TBL(f1) VALUES (' ');
25-
ERROR: invalid input syntax for typeinteger: " "
25+
ERROR: invalid input syntax for typesmallint: " "
2626
LINE 1: INSERT INTO INT2_TBL(f1) VALUES (' ');
2727
^
2828
INSERT INTO INT2_TBL(f1) VALUES ('- 1234');
29-
ERROR: invalid input syntax for typeinteger: "- 1234"
29+
ERROR: invalid input syntax for typesmallint: "- 1234"
3030
LINE 1: INSERT INTO INT2_TBL(f1) VALUES ('- 1234');
3131
^
3232
INSERT INTO INT2_TBL(f1) VALUES ('4 444');
33-
ERROR: invalid input syntax for typeinteger: "4 444"
33+
ERROR: invalid input syntax for typesmallint: "4 444"
3434
LINE 1: INSERT INTO INT2_TBL(f1) VALUES ('4 444');
3535
^
3636
INSERT INTO INT2_TBL(f1) VALUES ('123 dt');
37-
ERROR: invalid input syntax for typeinteger: "123 dt"
37+
ERROR: invalid input syntax for typesmallint: "123 dt"
3838
LINE 1: INSERT INTO INT2_TBL(f1) VALUES ('123 dt');
3939
^
4040
INSERT INTO INT2_TBL(f1) VALUES ('');
41-
ERROR: invalid input syntax for typeinteger: ""
41+
ERROR: invalid input syntax for typesmallint: ""
4242
LINE 1: INSERT INTO INT2_TBL(f1) VALUES ('');
4343
^
4444
SELECT '' AS five, * FROM INT2_TBL;

‎src/test/regress/expected/select_parallel.out

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -975,7 +975,7 @@ ROLLBACK TO SAVEPOINT settings;
975975
SAVEPOINT settings;
976976
SET LOCAL force_parallel_mode = 1;
977977
select stringu1::int2 from tenk1 where unique1 = 1;
978-
ERROR: invalid input syntax for typeinteger: "BAAAAA"
978+
ERROR: invalid input syntax for typesmallint: "BAAAAA"
979979
CONTEXT: parallel worker
980980
ROLLBACK TO SAVEPOINT settings;
981981
-- test interaction with set-returning functions

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp