I don't recognize the version 9.52C1. An Informix version might be 9.52.UC1 — with a choice from U
, F
, W
, H
, T
for the first letter. But then again, the main version numbers were 9.00..9.03, 9.10..9.16, 9.20, 9.21, 9.30, 9.40, 10.00, 11.10, 11.50, 11.70, 12.10 — a sequence which doesn't include a 9 and a 5 in a single version. Well, in many ways, it doesn't matter; any version 9.x has been out of support for most of a decade, if not longer, and shouldn't still be in use.
Assuming that an upgrade to a modern version of Informix is not in the cards, you are stuck with implementing your own functions. To do the job, you'd do best to implement them in C and install them as a package of UDRs (user-defined routines) in a shared library. That would give you the best performance. Assuming that's not feasible (I don't have a set of such functions on hand, but it shouldn't be hard to write them), then you have to fall back on SPL (stored procedure language) routines. These are not fast because of the limitations of SPL w.r.t substring operations — specifically, the built-in substring operations with []
notation do not accept variables as subscripts. That's really painful, to be polite about it.
Here's a version of char_at
which fetches a single character at a given position in a string of up to 255 characters:
-- @(#)$Id: char_at.spl,v 1.1 1999/05/17 23:59:59 jleffler Exp $
--
-- CHAR_AT stored procedure, to return character at given position in string
--
-- Author: J Leffler
-- Date: 1999-05-17
CREATE PROCEDURE char_at(str VARCHAR(255), pos SMALLINT) RETURNING CHAR(1);
DEFINE c CHAR(1);
IF pos > LENGTH(str) OR pos <= 0 THEN
LET c = NULL;
ELIF pos <= 16 THEN
IF pos = 1 THEN LET c = str[ 1];
ELIF pos = 2 THEN LET c = str[ 2];
ELIF pos = 3 THEN LET c = str[ 3];
ELIF pos = 4 THEN LET c = str[ 4];
ELIF pos = 5 THEN LET c = str[ 5];
ELIF pos = 6 THEN LET c = str[ 6];
ELIF pos = 7 THEN LET c = str[ 7];
ELIF pos = 8 THEN LET c = str[ 8];
ELIF pos = 9 THEN LET c = str[ 9];
ELIF pos = 10 THEN LET c = str[10];
ELIF pos = 11 THEN LET c = str[11];
ELIF pos = 12 THEN LET c = str[12];
ELIF pos = 13 THEN LET c = str[13];
ELIF pos = 14 THEN LET c = str[14];
ELIF pos = 15 THEN LET c = str[15];
ELIF pos = 16 THEN LET c = str[16];
END IF;
ELIF pos <= 32 THEN LET c = char_at(str[ 17, 32], pos - 1 * 16);
ELIF pos <= 48 THEN LET c = char_at(str[ 33, 48], pos - 2 * 16);
ELIF pos <= 64 THEN LET c = char_at(str[ 49, 64], pos - 3 * 16);
ELIF pos <= 80 THEN LET c = char_at(str[ 65, 80], pos - 4 * 16);
ELIF pos <= 96 THEN LET c = char_at(str[ 81, 96], pos - 5 * 16);
ELIF pos <= 112 THEN LET c = char_at(str[ 97,112], pos - 6 * 16);
ELIF pos <= 128 THEN LET c = char_at(str[113,128], pos - 7 * 16);
ELIF pos <= 144 THEN LET c = char_at(str[129,144], pos - 8 * 16);
ELIF pos <= 160 THEN LET c = char_at(str[145,160], pos - 9 * 16);
ELIF pos <= 176 THEN LET c = char_at(str[161,176], pos - 10 * 16);
ELIF pos <= 192 THEN LET c = char_at(str[177,192], pos - 11 * 16);
ELIF pos <= 208 THEN LET c = char_at(str[193,208], pos - 12 * 16);
ELIF pos <= 224 THEN LET c = char_at(str[209,224], pos - 13 * 16);
ELIF pos <= 240 THEN LET c = char_at(str[225,240], pos - 14 * 16);
ELIF pos <= 255 THEN LET c = char_at(str[241,255], pos - 15 * 16); -- Note asymmetry in upper bound!
ELSE LET c = NULL; -- Not reached!
END IF;
RETURN c;
END PROCEDURE;
Handling general substrings and the like is similarly painful. I've never gone to the effort of building even a semi-performant SPL implementation of SUBSTR
. It is far, far better to upgrade to a version of Informix that has the support built-in.
CHR() and ASCII()
The CHR()
. ASCII()
functions can be simulated with:
-- @(#)$Id: chr.sql,v 1.2 2008/09/19 18:48:37 jleffler Exp $
--
-- @(#)Procedure CHR() - return character corresponding to integer
CREATE PROCEDURE chr(i INTEGER) RETURNING CHAR(1) AS result;
DEFINE c CHAR;
IF i < 0 OR i > 255 THEN
RAISE EXCEPTION -746, 0, 'CHR(): integer value out of range 0..255';
END IF;
IF i = 0 OR i IS NULL THEN
LET c = NULL;
ELSE
SELECT chr INTO c FROM ascii WHERE val = i;
END IF;
RETURN c;
END PROCEDURE;
-- @(#)$Id: ascii.sql,v 1.2 2008/09/19 18:40:19 jleffler Exp $
--
-- Procedure ASCII - returning integer corresponding to character.
-- Misnomer: it works on any single-byte character.
CREATE PROCEDURE jl_ascii(C CHAR) RETURNING INT AS result;
DEFINE i INTEGER;
IF c IS NULL THEN
LET i = 0;
ELSE
SELECT val INTO i FROM ascii WHERE chr = c;
END IF;
RETURN i;
END PROCEDURE;
which requires a table:
-- @(#)$Id: asciitbl.sql,v 1.2 2005/03/30 17:51:12 jleffler Exp $
--
-- @(#)Create ASCII Table (for ASCII and CHR functions).
CREATE TABLE ascii
(
val INTEGER NOT NULL UNIQUE CONSTRAINT u1_ascii,
chr CHAR(1) NOT NULL UNIQUE CONSTRAINT u2_ascii
);
REVOKE ALL ON ascii FROM PUBLIC;
GRANT SELECT ON ascii TO PUBLIC;
and the data to go in it — 255 lines such as:
…
32|
33|!
34|"
35|#
36|$
37|%
38|&
39|'
40|(
…
64|@
65|A
66|B
67|C
68|D
69|E
…
You should be able to find a copy of this code at the IIUG under the name ascii.