On Thu, Dec 22, 2022 at 10:08:17AM +0000, Dag Lem wrote: > > The calculation of quotient and remainder can be replaced by less costly > masking and shifting. > > Defining > > #define OCT_DIGIT_BITS 3 > #define OCT_DIGIT_BITMASK 0x7 > > the content of the loop can be replaced by > > *--ptr = digits[value & OCT_DIGIT_BITMASK]; > value >>= OCT_DIGIT_BITS; > > Also, the check for ptr > buf in the while loop can be removed. The > check is superfluous, since buf cannot possibly be exhausted by a 32 > bit integer (the maximum octal number being 37777777777).
I integrated these suggestions in the attached -v2 patch and tested range of values manually. Also picked an OID > 8000 as suggested by unused_oids. ..Eric
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 1f63dc6dba..b539e0dc0b 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -3699,6 +3699,23 @@ repeat('Pg', 4) <returnvalue>PgPgPgPg</returnvalue> </para></entry> </row> + <row> + <entry role="func_table_entry"><para role="func_signature"> + <indexterm> + <primary>to_oct</primary> + </indexterm> + <function>to_oct</function> ( <type>integer</type> ) + <returnvalue>text</returnvalue> + </para> + <para> + Converts the number to its equivalent octal representation. + </para> + <para> + <literal>to_oct(32)</literal> + <returnvalue>40</returnvalue> + </para></entry> + </row> + <row> <entry role="func_table_entry"><para role="func_signature"> <indexterm> diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c index 1c52deec55..586693ad8f 100644 --- a/src/backend/utils/adt/varlena.c +++ b/src/backend/utils/adt/varlena.c @@ -5229,6 +5229,32 @@ to_hex64(PG_FUNCTION_ARGS) PG_RETURN_TEXT_P(cstring_to_text(ptr)); } +#define OCT_DIGIT_BITS 3 +#define OCT_DIGIT_BITMASK 0x7 +/* + * Convert an int32 to a string containing a base 8 (oct) representation of + * the number. + */ +Datum +to_oct32(PG_FUNCTION_ARGS) +{ + uint32 value = (uint32) PG_GETARG_INT32(0); + char *ptr; + const char *digits = "01234567"; + char buf[32]; /* bigger than needed, but reasonable */ + + ptr = buf + sizeof(buf) - 1; + *ptr = '\0'; + + do + { + *--ptr = digits[value & OCT_DIGIT_BITMASK]; + value >>= OCT_DIGIT_BITS; + } while (value); + + PG_RETURN_TEXT_P(cstring_to_text(ptr)); +} + /* * Return the size of a datum, possibly compressed * diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 98d90d9338..fde0b24563 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -3687,6 +3687,9 @@ { oid => '2090', descr => 'convert int8 number to hex', proname => 'to_hex', prorettype => 'text', proargtypes => 'int8', prosrc => 'to_hex64' }, +{ oid => '8335', descr => 'convert int4 number to oct', + proname => 'to_oct', prorettype => 'text', proargtypes => 'int4', + prosrc => 'to_oct32' }, # for character set encoding support diff --git a/src/test/regress/expected/strings.out b/src/test/regress/expected/strings.out index f028c1f10f..5ebaeb4a80 100644 --- a/src/test/regress/expected/strings.out +++ b/src/test/regress/expected/strings.out @@ -2143,6 +2143,15 @@ select to_hex(256::bigint*256::bigint*256::bigint*256::bigint - 1) AS "ffffffff" ffffffff (1 row) +-- +-- test to_oct +-- +select to_oct(256*256*256 - 1) AS "77777777"; + 77777777 +---------- + 77777777 +(1 row) + -- -- SHA-2 -- diff --git a/src/test/regress/sql/strings.sql b/src/test/regress/sql/strings.sql index 932f71cbca..c4c40949e7 100644 --- a/src/test/regress/sql/strings.sql +++ b/src/test/regress/sql/strings.sql @@ -691,6 +691,11 @@ select to_hex(256*256*256 - 1) AS "ffffff"; select to_hex(256::bigint*256::bigint*256::bigint*256::bigint - 1) AS "ffffffff"; +-- +-- test to_oct +-- +select to_oct(256*256*256 - 1) AS "77777777"; + -- -- SHA-2 --