Skip to content

Commit 260a1f1

Browse files
Add to_bin() and to_oct().
This commit introduces functions for converting numbers to their equivalent binary and octal representations. Also, the base conversion code for these functions and to_hex() has been moved to a common helper function. Co-authored-by: Eric Radman Reviewed-by: Ian Barwick, Dag Lem, Vignesh C, Tom Lane, Peter Eisentraut, Kirk Wolak, Vik Fearing, John Naylor, Dean Rasheed Discussion: https://postgr.es/m/Y6IyTQQ/TsD5wnsH%40vm3.eradman.com
1 parent ccadf73 commit 260a1f1

File tree

5 files changed

+204
-30
lines changed

5 files changed

+204
-30
lines changed

doc/src/sgml/func.sgml

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3737,6 +3737,32 @@ repeat('Pg', 4) <returnvalue>PgPgPgPg</returnvalue>
37373737
</para></entry>
37383738
</row>
37393739

3740+
<row>
3741+
<entry role="func_table_entry"><para role="func_signature">
3742+
<indexterm>
3743+
<primary>to_bin</primary>
3744+
</indexterm>
3745+
<function>to_bin</function> ( <type>integer</type> )
3746+
<returnvalue>text</returnvalue>
3747+
</para>
3748+
<para role="func_signature">
3749+
<function>to_bin</function> ( <type>bigint</type> )
3750+
<returnvalue>text</returnvalue>
3751+
</para>
3752+
<para>
3753+
Converts the number to its equivalent two's complement binary
3754+
representation.
3755+
</para>
3756+
<para>
3757+
<literal>to_bin(2147483647)</literal>
3758+
<returnvalue>1111111111111111111111111111111</returnvalue>
3759+
</para>
3760+
<para>
3761+
<literal>to_bin(-1234)</literal>
3762+
<returnvalue>11111111111111111111101100101110</returnvalue>
3763+
</para></entry>
3764+
</row>
3765+
37403766
<row>
37413767
<entry role="func_table_entry"><para role="func_signature">
37423768
<indexterm>
@@ -3750,11 +3776,42 @@ repeat('Pg', 4) <returnvalue>PgPgPgPg</returnvalue>
37503776
<returnvalue>text</returnvalue>
37513777
</para>
37523778
<para>
3753-
Converts the number to its equivalent hexadecimal representation.
3779+
Converts the number to its equivalent two's complement hexadecimal
3780+
representation.
37543781
</para>
37553782
<para>
37563783
<literal>to_hex(2147483647)</literal>
37573784
<returnvalue>7fffffff</returnvalue>
3785+
</para>
3786+
<para>
3787+
<literal>to_hex(-1234)</literal>
3788+
<returnvalue>fffffb2e</returnvalue>
3789+
</para></entry>
3790+
</row>
3791+
3792+
<row>
3793+
<entry role="func_table_entry"><para role="func_signature">
3794+
<indexterm>
3795+
<primary>to_oct</primary>
3796+
</indexterm>
3797+
<function>to_oct</function> ( <type>integer</type> )
3798+
<returnvalue>text</returnvalue>
3799+
</para>
3800+
<para role="func_signature">
3801+
<function>to_oct</function> ( <type>bigint</type> )
3802+
<returnvalue>text</returnvalue>
3803+
</para>
3804+
<para>
3805+
Converts the number to its equivalent two's complement octal
3806+
representation.
3807+
</para>
3808+
<para>
3809+
<literal>to_oct(2147483647)</literal>
3810+
<returnvalue>17777777777</returnvalue>
3811+
</para>
3812+
<para>
3813+
<literal>to_oct(-1234)</literal>
3814+
<returnvalue>37777775456</returnvalue>
37583815
</para></entry>
37593816
</row>
37603817

src/backend/utils/adt/varlena.c

Lines changed: 60 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4919,53 +4919,87 @@ array_to_text_internal(FunctionCallInfo fcinfo, ArrayType *v,
49194919
return result;
49204920
}
49214921

4922-
#define HEXBASE 16
49234922
/*
4924-
* Convert an int32 to a string containing a base 16 (hex) representation of
4925-
* the number.
4923+
* Workhorse for to_bin, to_oct, and to_hex. Note that base must be > 1 and <=
4924+
* 16.
49264925
*/
4927-
Datum
4928-
to_hex32(PG_FUNCTION_ARGS)
4926+
static inline text *
4927+
convert_to_base(uint64 value, int base)
49294928
{
4930-
uint32 value = (uint32) PG_GETARG_INT32(0);
4931-
char *ptr;
49324929
const char *digits = "0123456789abcdef";
4933-
char buf[32]; /* bigger than needed, but reasonable */
49344930

4935-
ptr = buf + sizeof(buf) - 1;
4936-
*ptr = '\0';
4931+
/* We size the buffer for to_bin's longest possible return value. */
4932+
char buf[sizeof(uint64) * BITS_PER_BYTE];
4933+
char *const end = buf + sizeof(buf);
4934+
char *ptr = end;
4935+
4936+
Assert(base > 1);
4937+
Assert(base <= 16);
49374938

49384939
do
49394940
{
4940-
*--ptr = digits[value % HEXBASE];
4941-
value /= HEXBASE;
4941+
*--ptr = digits[value % base];
4942+
value /= base;
49424943
} while (ptr > buf && value);
49434944

4944-
PG_RETURN_TEXT_P(cstring_to_text(ptr));
4945+
return cstring_to_text_with_len(ptr, end - ptr);
4946+
}
4947+
4948+
/*
4949+
* Convert an integer to a string containing a base-2 (binary) representation
4950+
* of the number.
4951+
*/
4952+
Datum
4953+
to_bin32(PG_FUNCTION_ARGS)
4954+
{
4955+
uint64 value = (uint32) PG_GETARG_INT32(0);
4956+
4957+
PG_RETURN_TEXT_P(convert_to_base(value, 2));
4958+
}
4959+
Datum
4960+
to_bin64(PG_FUNCTION_ARGS)
4961+
{
4962+
uint64 value = (uint64) PG_GETARG_INT64(0);
4963+
4964+
PG_RETURN_TEXT_P(convert_to_base(value, 2));
49454965
}
49464966

49474967
/*
4948-
* Convert an int64 to a string containing a base 16 (hex) representation of
4968+
* Convert an integer to a string containing a base-8 (oct) representation of
49494969
* the number.
49504970
*/
49514971
Datum
4952-
to_hex64(PG_FUNCTION_ARGS)
4972+
to_oct32(PG_FUNCTION_ARGS)
4973+
{
4974+
uint64 value = (uint32) PG_GETARG_INT32(0);
4975+
4976+
PG_RETURN_TEXT_P(convert_to_base(value, 8));
4977+
}
4978+
Datum
4979+
to_oct64(PG_FUNCTION_ARGS)
49534980
{
49544981
uint64 value = (uint64) PG_GETARG_INT64(0);
4955-
char *ptr;
4956-
const char *digits = "0123456789abcdef";
4957-
char buf[32]; /* bigger than needed, but reasonable */
49584982

4959-
ptr = buf + sizeof(buf) - 1;
4960-
*ptr = '\0';
4983+
PG_RETURN_TEXT_P(convert_to_base(value, 8));
4984+
}
49614985

4962-
do
4963-
{
4964-
*--ptr = digits[value % HEXBASE];
4965-
value /= HEXBASE;
4966-
} while (ptr > buf && value);
4986+
/*
4987+
* Convert an integer to a string containing a base-16 (hex) representation of
4988+
* the number.
4989+
*/
4990+
Datum
4991+
to_hex32(PG_FUNCTION_ARGS)
4992+
{
4993+
uint64 value = (uint32) PG_GETARG_INT32(0);
4994+
4995+
PG_RETURN_TEXT_P(convert_to_base(value, 16));
4996+
}
4997+
Datum
4998+
to_hex64(PG_FUNCTION_ARGS)
4999+
{
5000+
uint64 value = (uint64) PG_GETARG_INT64(0);
49675001

4968-
PG_RETURN_TEXT_P(cstring_to_text(ptr));
5002+
PG_RETURN_TEXT_P(convert_to_base(value, 16));
49695003
}
49705004

49715005
/*

src/include/catalog/pg_proc.dat

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3707,6 +3707,18 @@
37073707
{ oid => '2768', descr => 'split string by pattern',
37083708
proname => 'regexp_split_to_array', prorettype => '_text',
37093709
proargtypes => 'text text text', prosrc => 'regexp_split_to_array' },
3710+
{ oid => '9030', descr => 'convert int4 number to binary',
3711+
proname => 'to_bin', prorettype => 'text', proargtypes => 'int4',
3712+
prosrc => 'to_bin32' },
3713+
{ oid => '9031', descr => 'convert int8 number to binary',
3714+
proname => 'to_bin', prorettype => 'text', proargtypes => 'int8',
3715+
prosrc => 'to_bin64' },
3716+
{ oid => '9032', descr => 'convert int4 number to oct',
3717+
proname => 'to_oct', prorettype => 'text', proargtypes => 'int4',
3718+
prosrc => 'to_oct32' },
3719+
{ oid => '9033', descr => 'convert int8 number to oct',
3720+
proname => 'to_oct', prorettype => 'text', proargtypes => 'int8',
3721+
prosrc => 'to_oct64' },
37103722
{ oid => '2089', descr => 'convert int4 number to hex',
37113723
proname => 'to_hex', prorettype => 'text', proargtypes => 'int4',
37123724
prosrc => 'to_hex32' },

src/test/regress/expected/strings.out

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2129,8 +2129,68 @@ select split_part('@joeuser@mydatabase@','@',-2) AS "mydatabase";
21292129
(1 row)
21302130

21312131
--
2132-
-- test to_hex
2132+
-- test to_bin, to_oct, and to_hex
21332133
--
2134+
select to_bin(-1234) AS "11111111111111111111101100101110";
2135+
11111111111111111111101100101110
2136+
----------------------------------
2137+
11111111111111111111101100101110
2138+
(1 row)
2139+
2140+
select to_bin(-1234::bigint);
2141+
to_bin
2142+
------------------------------------------------------------------
2143+
1111111111111111111111111111111111111111111111111111101100101110
2144+
(1 row)
2145+
2146+
select to_bin(256*256*256 - 1) AS "111111111111111111111111";
2147+
111111111111111111111111
2148+
--------------------------
2149+
111111111111111111111111
2150+
(1 row)
2151+
2152+
select to_bin(256::bigint*256::bigint*256::bigint*256::bigint - 1) AS "11111111111111111111111111111111";
2153+
11111111111111111111111111111111
2154+
----------------------------------
2155+
11111111111111111111111111111111
2156+
(1 row)
2157+
2158+
select to_oct(-1234) AS "37777775456";
2159+
37777775456
2160+
-------------
2161+
37777775456
2162+
(1 row)
2163+
2164+
select to_oct(-1234::bigint) AS "1777777777777777775456";
2165+
1777777777777777775456
2166+
------------------------
2167+
1777777777777777775456
2168+
(1 row)
2169+
2170+
select to_oct(256*256*256 - 1) AS "77777777";
2171+
77777777
2172+
----------
2173+
77777777
2174+
(1 row)
2175+
2176+
select to_oct(256::bigint*256::bigint*256::bigint*256::bigint - 1) AS "37777777777";
2177+
37777777777
2178+
-------------
2179+
37777777777
2180+
(1 row)
2181+
2182+
select to_hex(-1234) AS "fffffb2e";
2183+
fffffb2e
2184+
----------
2185+
fffffb2e
2186+
(1 row)
2187+
2188+
select to_hex(-1234::bigint) AS "fffffffffffffb2e";
2189+
fffffffffffffb2e
2190+
------------------
2191+
fffffffffffffb2e
2192+
(1 row)
2193+
21342194
select to_hex(256*256*256 - 1) AS "ffffff";
21352195
ffffff
21362196
--------

src/test/regress/sql/strings.sql

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -685,10 +685,21 @@ select split_part('joeuser@mydatabase','@',-3) AS "empty string";
685685
select split_part('@joeuser@mydatabase@','@',-2) AS "mydatabase";
686686

687687
--
688-
-- test to_hex
688+
-- test to_bin, to_oct, and to_hex
689689
--
690-
select to_hex(256*256*256 - 1) AS "ffffff";
690+
select to_bin(-1234) AS "11111111111111111111101100101110";
691+
select to_bin(-1234::bigint);
692+
select to_bin(256*256*256 - 1) AS "111111111111111111111111";
693+
select to_bin(256::bigint*256::bigint*256::bigint*256::bigint - 1) AS "11111111111111111111111111111111";
694+
695+
select to_oct(-1234) AS "37777775456";
696+
select to_oct(-1234::bigint) AS "1777777777777777775456";
697+
select to_oct(256*256*256 - 1) AS "77777777";
698+
select to_oct(256::bigint*256::bigint*256::bigint*256::bigint - 1) AS "37777777777";
691699

700+
select to_hex(-1234) AS "fffffb2e";
701+
select to_hex(-1234::bigint) AS "fffffffffffffb2e";
702+
select to_hex(256*256*256 - 1) AS "ffffff";
692703
select to_hex(256::bigint*256::bigint*256::bigint*256::bigint - 1) AS "ffffffff";
693704

694705
--

0 commit comments

Comments
 (0)