CREATE OR REPLACE FUNCTION f_words_usd(p_number NUMERIC) RETURNS VARCHAR AS $$ DECLARE l_str TEXT[] := ARRAY['', 'thousand', 'million', 'billion', 'trillion', 'quadrillion', 'quintillion', 'sextillion', 'septillion', 'octillion', 'nonillion', 'decillion', 'undecillion', 'duodecillion']; units TEXT[] := ARRAY['', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine']; teens TEXT[] := ARRAY['eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen']; tens TEXT[] := ARRAY['', 'ten', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety']; l_num VARCHAR := TRUNC(p_number)::VARCHAR; l_return TEXT := ''; l_decimal NUMERIC; l_return_decimal TEXT := ''; i INTEGER; segment_len INTEGER; segment INT; segment_text TEXT; -- Helper function to convert a three-digit segment to words FUNCTION three_digit_to_words(segment INT) RETURNS TEXT AS $$ DECLARE hundred_part INT; ten_part INT; unit_part INT; segment_words TEXT := ''; BEGIN hundred_part := segment / 100; ten_part := (segment % 100) / 10; unit_part := segment % 10; IF hundred_part > 0 THEN segment_words := segment_words || units[hundred_part + 1] || ' hundred '; END IF; IF ten_part = 1 AND unit_part > 0 THEN segment_words := segment_words || teens[unit_part] || ' '; ELSE IF ten_part > 0 THEN segment_words := segment_words || tens[ten_part + 1] || ' '; END IF; IF unit_part > 0 THEN segment_words := segment_words || units[unit_part + 1] || ' '; END IF; END IF; RETURN segment_words; END; $$ LANGUAGE plpgsql; BEGIN -- Calculate decimal part l_decimal := p_number - TRUNC(p_number); FOR i IN 1 .. array_length(l_str, 1) LOOP EXIT WHEN l_num IS NULL OR l_num = ''; segment_len := GREATEST(LENGTH(l_num) - 2, 1); segment := SUBSTR(l_num, segment_len, 3)::INT; IF segment <> 0 THEN segment_text := three_digit_to_words(segment); l_return := segment_text || l_str[i] || ' ' || l_return; END IF; l_num := LEFT(l_num, GREATEST(LENGTH(l_num) - 3, 0)); END LOOP; IF l_return IS NOT NULL THEN l_return := l_return || 'US Dollar '; END IF; -- Handle decimal part IF l_decimal != 0 THEN l_decimal := l_decimal * 100; segment_text := three_digit_to_words(l_decimal::INT); l_return := l_return || 'and ' || segment_text || 'Cents '; END IF; IF l_return IS NOT NULL THEN l_return := l_return || 'Only'; END IF; RETURN l_return; END; $$ LANGUAGE plpgsql;