I am trying to debug a function not created by me ( dms2dd ). I made my own test function (see below) and cast my problem back to a specific line / value.
If I run the following query:
SELECT "Lat", "Long", test_dolf("Lat"), test_dolf("Long") FROM pawikan WHERE "Lat" IS NOT NULL AND "Long" IS NOT NULL ORDER BY index LIMIT 1 OFFSET 29130
I get the following output:
'N6Β° 6' 9.4824"';'E118Β° 26' 49.1172'' ';'9.4824';'49.1172'
what i expect. But with the following query:
SELECT "Lat", "Long", CAST(test_dolf("Lat") as numeric), test_dolf("Long") FROM pawikan WHERE "Lat" IS NOT NULL AND "Long" IS NOT NULL ORDER BY index LIMIT 1 OFFSET 29130
I get an error
ERROR: invalid input syntax for type numeric: "" SQL state: 22P02
The error indicates that the varchar value that I am trying to use for numeric is empty, but as you can see from the previous query, it is not. This is just a valid numeric varchar. In fact, if I copy-paste the value and run:
SELECT CAST('9.4824' AS numeric);
This fully works, and in fact the query results in a valid numeric. Moreover, if I save the results of the first query in a staging table with:
SELECT "Lat", "Long", test_dolf("Lat") as lat_sec, test_dolf("Long") as long_sec INTO dms2dd_test FROM pawikan WHERE "Lat" IS NOT NULL AND "Long" IS NOT NULL ORDER BY index LIMIT 11 OFFSET 29120
and then enter
SELECT CAST(long_sec as numeric), CAST(lat_sec AS numeric) FROM dms2dd_test;
It works completely. Even this works great:
SELECT test_dolf(E'N6Β° 6\' 9.4824"')::numeric as lat_sec
So what is going on here? It seems that in the second query, in which I passed a numerical value, another value is passed to my function, but I tested the sort column (index) and contains only unique bandages.
This is the code for the test_dolf function:
CREATE OR REPLACE FUNCTION public.test_dolf(strdegminsec character varying) RETURNS varchar AS $BODY$ DECLARE i numeric; intDmsLen numeric; -- Length of original string strCompassPoint Char(1); strNorm varchar(16) = ''; -- Will contain normalized string strDegMinSecB varchar(100); blnGotSeparator integer; -- Keeps track of separator sequences arrDegMinSec varchar[]; -- TYPE stringarray is table of varchar(2048) ; strChr Char(1); BEGIN strDegMinSec := regexp_replace(replace(strdegminsec,E'\'\'','"'),' "([0-9]+)',E' \\1"'); -- Remove leading and trailing spaces strDegMinSecB := REPLACE(strDegMinSec,' ',''); intDmsLen := Length(strDegMinSecB); blnGotSeparator := 0; -- Not in separator sequence right now -- Loop over string, replacing anything that is not a digit or a -- decimal separator with -- a single blank FOR i in 1..intDmsLen LOOP -- Get current character strChr := SubStr(strDegMinSecB, i, 1); -- either add character to normalized string or replace -- separator sequence with single blank If strpos('0123456789,.', strChr) > 0 Then -- add character but replace comma with point If (strChr <> ',') Then strNorm := strNorm || strChr; Else strNorm := strNorm || '.'; End If; blnGotSeparator := 0; ElsIf strpos('neswNESW',strChr) > 0 Then -- Extract Compass Point if present strCompassPoint := strChr; Else -- ensure only one separator is replaced with a blank - -- suppress the rest If blnGotSeparator = 0 Then strNorm := strNorm || ' '; blnGotSeparator := 0; End If; End If; End Loop; -- Split normalized string into array of max 3 components arrDegMinSec := string_to_array(strNorm, ' '); return arrDegMinSec[3]; End $BODY$ LANGUAGE plpgsql IMMUTABLE COST 100;