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

Commite61fd4a

Browse files
committed
Support EEEE (scientific notation) in to_char().
Pavel Stehule, Brendan Jurd
1 parent933b17b commite61fd4a

File tree

6 files changed

+347
-14
lines changed

6 files changed

+347
-14
lines changed

‎doc/src/sgml/func.sgml

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.485 2009/08/1016:10:19 tgl Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.486 2009/08/1018:29:26 tgl Exp $ -->
22

33
<chapter id="functions">
44
<title>Functions and Operators</title>
@@ -5345,7 +5345,7 @@ SELECT SUBSTRING('XY1234Z', 'Y*?([0-9]{1,3})');
53455345
</row>
53465346
<row>
53475347
<entry><literal>EEEE</literal></entry>
5348-
<entry>scientific notation (not implemented)</entry>
5348+
<entry>exponent for scientific notation</entry>
53495349
</row>
53505350
</tbody>
53515351
</tgroup>
@@ -5404,6 +5404,15 @@ SELECT SUBSTRING('XY1234Z', 'Y*?([0-9]{1,3})');
54045404
(e.g., <literal>99.9V99</literal> is not allowed).
54055405
</para>
54065406
</listitem>
5407+
5408+
<listitem>
5409+
<para>
5410+
<literal>EEEE</literal> (scientific notation) cannot be used in
5411+
combination with any of the other special formatting patterns or
5412+
modifiers, and must be at the end of the format string
5413+
(e.g., <literal>9.99EEEE</literal> is a valid pattern).
5414+
</para>
5415+
</listitem>
54075416
</itemizedlist>
54085417
</para>
54095418

@@ -5605,6 +5614,10 @@ SELECT SUBSTRING('XY1234Z', 'Y*?([0-9]{1,3})');
56055614
<entry><literal>to_char(12.45, '99V9')</literal></entry>
56065615
<entry><literal>'&nbsp;125'</literal></entry>
56075616
</row>
5617+
<row>
5618+
<entry><literal>to_char(0.0004859, '9.99EEEE')</literal></entry>
5619+
<entry><literal>' 4.86e-04'</literal></entry>
5620+
</row>
56085621
</tbody>
56095622
</tgroup>
56105623
</table>

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

Lines changed: 178 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* -----------------------------------------------------------------------
22
* formatting.c
33
*
4-
* $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.159 2009/07/06 19:11:39 heikki Exp $
4+
* $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.160 2009/08/10 18:29:26 tgl Exp $
55
*
66
*
77
* Portions Copyright (c) 1999-2009, PostgreSQL Global Development Group
@@ -335,6 +335,7 @@ typedef struct
335335
#defineNUM_F_MULTI(1 << 11)
336336
#defineNUM_F_PLUS_POST(1 << 12)
337337
#defineNUM_F_MINUS_POST(1 << 13)
338+
#defineNUM_F_EEEE(1 << 14)
338339

339340
#defineNUM_LSIGN_PRE(-1)
340341
#defineNUM_LSIGN_POST1
@@ -355,6 +356,7 @@ typedef struct
355356
#defineIS_PLUS(_f) ((_f)->flag & NUM_F_PLUS)
356357
#defineIS_ROMAN(_f)((_f)->flag & NUM_F_ROMAN)
357358
#defineIS_MULTI(_f)((_f)->flag & NUM_F_MULTI)
359+
#defineIS_EEEE(_f)((_f)->flag & NUM_F_EEEE)
358360

359361
/* ----------
360362
* Format picture cache
@@ -821,7 +823,7 @@ static const KeyWord NUM_keywords[] = {
821823
{"B",1,NUM_B},/* B */
822824
{"C",1,NUM_C},/* C */
823825
{"D",1,NUM_D},/* D */
824-
{"E",1,NUM_E},/* E */
826+
{"EEEE",4,NUM_E},/* E */
825827
{"FM",2,NUM_FM},/* F */
826828
{"G",1,NUM_G},/* G */
827829
{"L",1,NUM_L},/* L */
@@ -837,7 +839,7 @@ static const KeyWord NUM_keywords[] = {
837839
{"b",1,NUM_B},/* b */
838840
{"c",1,NUM_C},/* c */
839841
{"d",1,NUM_D},/* d */
840-
{"e",1,NUM_E},/* e */
842+
{"eeee",4,NUM_E},/* e */
841843
{"fm",2,NUM_FM},/* f */
842844
{"g",1,NUM_G},/* g */
843845
{"l",1,NUM_L},/* l */
@@ -1044,6 +1046,14 @@ NUMDesc_prepare(NUMDesc *num, FormatNode *n)
10441046
if (n->type!=NODE_TYPE_ACTION)
10451047
return;
10461048

1049+
if (IS_EEEE(num)&&n->key->id!=NUM_E)
1050+
{
1051+
NUM_cache_remove(last_NUMCacheEntry);
1052+
ereport(ERROR,
1053+
(errcode(ERRCODE_SYNTAX_ERROR),
1054+
errmsg("\"EEEE\" must be the last pattern used")));
1055+
}
1056+
10471057
switch (n->key->id)
10481058
{
10491059
caseNUM_9:
@@ -1217,10 +1227,25 @@ NUMDesc_prepare(NUMDesc *num, FormatNode *n)
12171227
break;
12181228

12191229
caseNUM_E:
1220-
NUM_cache_remove(last_NUMCacheEntry);
1221-
ereport(ERROR,
1222-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1223-
errmsg("\"E\" is not supported")));
1230+
if (IS_EEEE(num))
1231+
{
1232+
NUM_cache_remove(last_NUMCacheEntry);
1233+
ereport(ERROR,
1234+
(errcode(ERRCODE_SYNTAX_ERROR),
1235+
errmsg("cannot use \"EEEE\" twice")));
1236+
}
1237+
if (IS_BLANK(num)||IS_FILLMODE(num)||IS_LSIGN(num)||
1238+
IS_BRACKET(num)||IS_MINUS(num)||IS_PLUS(num)||
1239+
IS_ROMAN(num)||IS_MULTI(num))
1240+
{
1241+
NUM_cache_remove(last_NUMCacheEntry);
1242+
ereport(ERROR,
1243+
(errcode(ERRCODE_SYNTAX_ERROR),
1244+
errmsg("\"EEEE\" is incompatible with other formats"),
1245+
errdetail("\"EEEE\" may only be used together with digit and decimal point patterns.")));
1246+
}
1247+
num->flag |=NUM_F_EEEE;
1248+
break;
12241249
}
12251250

12261251
return;
@@ -4145,6 +4170,15 @@ NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number,
41454170
if (Np->Num->zero_start)
41464171
--Np->Num->zero_start;
41474172

4173+
if (IS_EEEE(Np->Num))
4174+
{
4175+
if (!Np->is_to_char)
4176+
ereport(ERROR,
4177+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4178+
errmsg("\"EEEE\" not supported for input")));
4179+
returnstrcpy(inout,number);
4180+
}
4181+
41484182
/*
41494183
* Roman correction
41504184
*/
@@ -4153,7 +4187,7 @@ NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number,
41534187
if (!Np->is_to_char)
41544188
ereport(ERROR,
41554189
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4156-
errmsg("\"RN\" not supported")));
4190+
errmsg("\"RN\" not supported for input")));
41574191

41584192
Np->Num->lsign=Np->Num->pre_lsign_num=Np->Num->post=
41594193
Np->Num->pre=Np->num_pre=Np->sign=0;
@@ -4240,7 +4274,7 @@ NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number,
42404274

42414275
#ifdefDEBUG_TO_FROM_CHAR
42424276
elog(DEBUG_elog_output,
4243-
"\n\tSIGN: '%c'\n\tNUM: '%s'\n\tPRE: %d\n\tPOST: %d\n\tNUM_COUNT: %d\n\tNUM_PRE: %d\n\tSIGN_WROTE: %s\n\tZERO: %s\n\tZERO_START: %d\n\tZERO_END: %d\n\tLAST_RELEVANT: %s\n\tBRACKET: %s\n\tPLUS: %s\n\tMINUS: %s\n\tFILLMODE: %s\n\tROMAN: %s",
4277+
"\n\tSIGN: '%c'\n\tNUM: '%s'\n\tPRE: %d\n\tPOST: %d\n\tNUM_COUNT: %d\n\tNUM_PRE: %d\n\tSIGN_WROTE: %s\n\tZERO: %s\n\tZERO_START: %d\n\tZERO_END: %d\n\tLAST_RELEVANT: %s\n\tBRACKET: %s\n\tPLUS: %s\n\tMINUS: %s\n\tFILLMODE: %s\n\tROMAN: %s\n\tEEEE: %s",
42444278
Np->sign,
42454279
Np->number,
42464280
Np->Num->pre,
@@ -4256,7 +4290,8 @@ NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number,
42564290
IS_PLUS(Np->Num) ?"Yes" :"No",
42574291
IS_MINUS(Np->Num) ?"Yes" :"No",
42584292
IS_FILLMODE(Np->Num) ?"Yes" :"No",
4259-
IS_ROMAN(Np->Num) ?"Yes" :"No"
4293+
IS_ROMAN(Np->Num) ?"Yes" :"No",
4294+
IS_EEEE(Np->Num) ?"Yes" :"No"
42604295
);
42614296
#endif
42624297

@@ -4626,6 +4661,39 @@ numeric_to_char(PG_FUNCTION_ARGS)
46264661
int_to_roman(DatumGetInt32(DirectFunctionCall1(numeric_int4,
46274662
NumericGetDatum(x))));
46284663
}
4664+
elseif (IS_EEEE(&Num))
4665+
{
4666+
orgnum=numeric_out_sci(value,Num.post);
4667+
4668+
/*
4669+
* numeric_out_sci() does not emit a sign for positive numbers. We
4670+
* need to add a space in this case so that positive and negative
4671+
* numbers are aligned. We also have to do the right thing for NaN.
4672+
*/
4673+
if (strcmp(orgnum,"NaN")==0)
4674+
{
4675+
/*
4676+
* Allow 6 characters for the leading sign, the decimal point, "e",
4677+
* the exponent's sign and two exponent digits.
4678+
*/
4679+
numstr= (char*)palloc(Num.pre+Num.post+7);
4680+
fill_str(numstr,'#',Num.pre+Num.post+6);
4681+
*numstr=' ';
4682+
*(numstr+Num.pre+1)='.';
4683+
}
4684+
elseif (*orgnum!='-')
4685+
{
4686+
numstr= (char*)palloc(strlen(orgnum)+2);
4687+
*numstr=' ';
4688+
strcpy(numstr+1,orgnum);
4689+
len=strlen(numstr);
4690+
}
4691+
else
4692+
{
4693+
numstr=orgnum;
4694+
len=strlen(orgnum);
4695+
}
4696+
}
46294697
else
46304698
{
46314699
Numericval=value;
@@ -4707,6 +4775,23 @@ int4_to_char(PG_FUNCTION_ARGS)
47074775
*/
47084776
if (IS_ROMAN(&Num))
47094777
numstr=orgnum=int_to_roman(value);
4778+
elseif (IS_EEEE(&Num))
4779+
{
4780+
/* we can do it easily because float8 won't lose any precision */
4781+
float8val= (float8)value;
4782+
4783+
orgnum= (char*)palloc(MAXDOUBLEWIDTH+1);
4784+
snprintf(orgnum,MAXDOUBLEWIDTH+1,"%+.*e",Num.post,val);
4785+
4786+
/*
4787+
* Swap a leading positive sign for a space.
4788+
*/
4789+
if (*orgnum=='+')
4790+
*orgnum=' ';
4791+
4792+
len=strlen(orgnum);
4793+
numstr=orgnum;
4794+
}
47104795
else
47114796
{
47124797
if (IS_MULTI(&Num))
@@ -4785,6 +4870,33 @@ int8_to_char(PG_FUNCTION_ARGS)
47854870
numstr=orgnum=int_to_roman(DatumGetInt32(
47864871
DirectFunctionCall1(int84,Int64GetDatum(value))));
47874872
}
4873+
elseif (IS_EEEE(&Num))
4874+
{
4875+
/* to avoid loss of precision, must go via numeric not float8 */
4876+
Numericval;
4877+
4878+
val=DatumGetNumeric(DirectFunctionCall1(int8_numeric,
4879+
Int64GetDatum(value)));
4880+
orgnum=numeric_out_sci(val,Num.post);
4881+
4882+
/*
4883+
* numeric_out_sci() does not emit a sign for positive numbers. We
4884+
* need to add a space in this case so that positive and negative
4885+
* numbers are aligned. We don't have to worry about NaN here.
4886+
*/
4887+
if (*orgnum!='-')
4888+
{
4889+
numstr= (char*)palloc(strlen(orgnum)+2);
4890+
*numstr=' ';
4891+
strcpy(numstr+1,orgnum);
4892+
len=strlen(numstr);
4893+
}
4894+
else
4895+
{
4896+
numstr=orgnum;
4897+
len=strlen(orgnum);
4898+
}
4899+
}
47884900
else
47894901
{
47904902
if (IS_MULTI(&Num))
@@ -4859,6 +4971,34 @@ float4_to_char(PG_FUNCTION_ARGS)
48594971

48604972
if (IS_ROMAN(&Num))
48614973
numstr=orgnum=int_to_roman((int)rint(value));
4974+
elseif (IS_EEEE(&Num))
4975+
{
4976+
numstr=orgnum= (char*)palloc(MAXDOUBLEWIDTH+1);
4977+
if (isnan(value)||is_infinite(value))
4978+
{
4979+
/*
4980+
* Allow 6 characters for the leading sign, the decimal point, "e",
4981+
* the exponent's sign and two exponent digits.
4982+
*/
4983+
numstr= (char*)palloc(Num.pre+Num.post+7);
4984+
fill_str(numstr,'#',Num.pre+Num.post+6);
4985+
*numstr=' ';
4986+
*(numstr+Num.pre+1)='.';
4987+
}
4988+
else
4989+
{
4990+
snprintf(orgnum,MAXDOUBLEWIDTH+1,"%+.*e",Num.post,value);
4991+
4992+
/*
4993+
* Swap a leading positive sign for a space.
4994+
*/
4995+
if (*orgnum=='+')
4996+
*orgnum=' ';
4997+
4998+
len=strlen(orgnum);
4999+
numstr=orgnum;
5000+
}
5001+
}
48625002
else
48635003
{
48645004
float4val=value;
@@ -4935,6 +5075,34 @@ float8_to_char(PG_FUNCTION_ARGS)
49355075

49365076
if (IS_ROMAN(&Num))
49375077
numstr=orgnum=int_to_roman((int)rint(value));
5078+
elseif (IS_EEEE(&Num))
5079+
{
5080+
numstr=orgnum= (char*)palloc(MAXDOUBLEWIDTH+1);
5081+
if (isnan(value)||is_infinite(value))
5082+
{
5083+
/*
5084+
* Allow 6 characters for the leading sign, the decimal point, "e",
5085+
* the exponent's sign and two exponent digits.
5086+
*/
5087+
numstr= (char*)palloc(Num.pre+Num.post+7);
5088+
fill_str(numstr,'#',Num.pre+Num.post+6);
5089+
*numstr=' ';
5090+
*(numstr+Num.pre+1)='.';
5091+
}
5092+
else
5093+
{
5094+
snprintf(orgnum,MAXDOUBLEWIDTH+1,"%+.*e",Num.post,value);
5095+
5096+
/*
5097+
* Swap a leading positive sign for a space.
5098+
*/
5099+
if (*orgnum=='+')
5100+
*orgnum=' ';
5101+
5102+
len=strlen(orgnum);
5103+
numstr=orgnum;
5104+
}
5105+
}
49385106
else
49395107
{
49405108
float8val=value;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp