Subject | Re: [firebird-support] Selecting records based on a list of ids (sp parameter) |
---|---|
Author | Rafael Szuminski |
Post date | 2004-04-07T15:16:47Z |
Helen,
thanks for the pointer to the substring function, btw. the issue with the UDF
was resolved by restarting just the FB server.
raf
Helen Borrie wrote:
Rafael Szuminski
Email:raf@...
Phone:(949)939 - 2458
www.BDCSoftware.com
thanks for the pointer to the substring function, btw. the issue with the UDF
was resolved by restarting just the FB server.
raf
Helen Borrie wrote:
> At 02:16 PM 6/04/2004 -0700, you wrote:--
>
>
>>Of course no solution is perfect. With this one I have run into issues
>>regarding
>>the 80 characters limit on the substr and substrlen functions. I tried
>>increasing this in the function declaration, but no matter what I increase
>>it to
>>I always get an overflow error when I pass more then 80 char to it. Has
>>anybody
>>experienced the same issue with substr and substrlen?
>
>
> According to Claudio, who has done a lot of stuff with the UDF libraries,
> the "token length" rule for UDF declarations has been gone since IB
> 5.0. So it seems the "token" string argument size is a long-standing
> documentation bug.
>
> There are two possible issues here. One is that you have to declare string
> UDFs with an input string long enough to take the data they will
> receive. The other is that, for Firebird, the substr UDF is deprecated in
> favour of the internal SUBSTRING function. SUBSTRING is not particular
> about the length of a string, as long as it is within the 32,765-byte limit
> for varchars.
>
> "Changing the declaration" won't change the size of input that your SP or
> trigger expects to get. You need to
> 1) drop the procedure or trigger
> 2) drop the function (DROP EXTERNAL FUNCTION) (if you have no other objects
> dependent on it) and declare it anew
> ** or **
> add another declaration for that function, with a different <function-name>
> and an input that is large enough
> 3) recreate the trigger or procedure using the name of the newly-declared
> function
> 4) and, of course, if you are on Windows, reboot the machine to unload the
> old dll.
>
> I don't use the substr() function myself at all for Firebird; but we'll
> use it as an example, because the same applies to all string functions.
>
> Here's the sample declaration from ib_udf.sql:
>
> DECLARE EXTERNAL FUNCTION substr
> CSTRING(80), SMALLINT, SMALLINT
> RETURNS CSTRING(80) FREE_IT
> ENTRY_POINT 'IB_UDF_substr' MODULE_NAME 'ib_udf';
>
> You can keep this if you have other objects using it that can tolerate the
> 80-byte maximum. For this SP and others that need e.g. a 1 Kb max. byte
> size, you add:
>
> DECLARE EXTERNAL FUNCTION substr1K
> CSTRING(1024), SMALLINT, SMALLINT
> RETURNS CSTRING(1024) FREE_IT
> ENTRY_POINT 'IB_UDF_substr' MODULE_NAME 'ib_udf';
>
> Then, you might need a function that takes a longer string. You need
> another declaration:
> DECLARE EXTERNAL FUNCTION substr2K
> CSTRING(2048), SMALLINT, SMALLINT
> RETURNS CSTRING(2048) FREE_IT
> ENTRY_POINT 'IB_UDF_substr' MODULE_NAME 'ib_udf';
>
> Now, you could argue that it would be better to declare substr once with an
> argument of 32765 and be done with it. However, it's a rare requirement to
> be trying to do a string function on a string so large. Yet this would
> force the system to allocate memory this large each time it calls the
> function, even if it's only analysing a string of 10 bytes. If you are
> using it for grouping or ordering, the function is going to be called twice
> per row (ordering) or once per row and once per group (grouping). IOW,
> each time it gets named explicitly, or implicitly by its degree number, it
> gets called and has to allocate 32 Kb.
>
> With respect to substr, you'd be better to replace it with SUBSTRING(). In
> SPs, to massage strings, there are more efficient things you can do using
> SUBSTRING(), in preference to calling a UDF. However, ordering and
> grouping by UDF expressions isn't one of those things.
>
> Have you considered this solution, for example:
>
> CREATE PROCEDURE PROC_TEST (
> M_LIST VARCHAR (100)) /* replace with the max.bytelength you need */
> RETURNS (
> R_ID INTEGER)
> AS
> declare variable r_id_string varchar(10);
> declare variable cur_char char;
> declare variable isdone char = '0';
> BEGIN
> r_id = -1;
> r_id_string = '';
> while (isdone = '0') do
> begin
> cur_char = substring(m_list from 1 for 1);
> if (cur_char <> ',') then
> r_id_string = r_id_string || cur_char;
>
> if (cur_char = '') then
> isdone = '1';
> if (cur_char = ',' or isdone = '1') then
> begin
> if (r_id_string <> '') then
> r_id = cast(r_id_string as integer);
> SUSPEND;
> r_id = -1;
> r_id_string = '';
> end
> m_list = substring(m_list from 2);
> end
> end
>
> /heLen
>
>
>
>
> Yahoo! Groups Links
>
>
>
>
>
>
Rafael Szuminski
Email:raf@...
Phone:(949)939 - 2458
www.BDCSoftware.com