Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

return by descriptor UDF char parametr trunc for 1/4 of it`s len if UDF set paramdsc->dsc_sub_type to UTF8 [CORE5983] #6235

Open
firebird-automations opened this issue Jan 13, 2019 · 8 comments

Comments

@firebird-automations
Copy link
Collaborator

Submitted by: Segey Khalyutin (notesoft)

database default charset is UTF8

in UDF i`m set paramdsc->dsc_sub_type to UTF8 like this:

 private void assign\_sub\_type\(byte charset, byte collation\) 
 \{         
     this\.sub\_type = \(short\) \(\(collation\) << 8 \| \(charset\)\); 
 \}
 assign\_sub\_type\(4, 4\); 

when UDF is return parametr to stored ptocedure the value len trunc for 1/4 of it`s len

value in UDF '123-123-123-123' has '123-' in stored procedure/

if i`m set paramdsc->dsc_sub_type = 0 return value id normal '123-123-123-123' as needed

Query:

NO bug in engine, I`m mast set paramdsc->dsc_sub_type = 0; in UDF for UTF8 strings
or
trunc for 1/4 is bug in engine, I`m mast set paramdsc->dsc_sub_type = (short) ((collation) << 8 | (charset));
or
I`m don`t understood something...

@firebird-automations
Copy link
Collaborator Author

Modified by: Segey Khalyutin (notesoft)

summary: return by descriptor UDF varchar parametr trunc for 1/4 of it`s len if UD8 set paramdsc->dsc_sub_type to UTF8 => return by descriptor UDF varchar parametr trunc for 1/4 of it`s len if UDF set paramdsc->dsc_sub_type to UTF8

@firebird-automations
Copy link
Collaborator Author

Commented by: @asfernandes

Please post minimal UDF source code, SQL declaration and how do you observe the problem with an ISQL script.

So far my tests using sNvl from FB code doesn't reproduce the problem.

@firebird-automations
Copy link
Collaborator Author

Commented by: Segey Khalyutin (notesoft)

main.cpp ===============================================

/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/

#⁠include "main.h"

int main(int argc, char** argv)
{
return (EXIT_SUCCESS);
}

/*

declare external function test_of_dsc_sub_type
integer by descriptor
, varchar(255) by descriptor
returns
parameter 2
entry_point 'testof_dsc_sub_type' module_name 'fb_udf_test'

*/

NM\_EXPORT void testof\_dsc\_sub\_type\(paramdsc\* param, paramdsc\* result\)
\{        
  	ISC\_LONG val = \*\(\(ISC\_LONG\*\)\(param\-\>dsc\_address\)\);
           
    short        charset = val == 4 ? 4 : 0;
    short       collation = val == 4 ? 4 : 0;        
    const char\*  value = val == 4 ? "The quick brown fox jumps over the lazy dog\."
                                                  :    "the quick brown fox jumps over the lazy dog";

    int            len = strlen\(value\);                
                    
    result\-\>dsc\_dtype       = dtype\_text;
    result\-\>dsc\_scale       = 0;
    result\-\>dsc\_length      = len; 
    result\-\>dsc\_sub\_type = \(short\)\(\(collation\) << 8 \| \(charset\)\); 
    result\-\>dsc\_flags        = 0;
    result\-\>dsc\_address   = \(ISC\_UCHAR\*\)value;
\}

main.h=================================================

/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/

/*
* File: fbudf.h
* Author: khalyutin
*
* Created on January 25, 2019, 2:06 PM
*/

#⁠ifndef FBUDF_H
#⁠define FBUDF_H

#⁠ifdef __cplusplus
extern "C" {
#⁠endif

#⁠include <ibase.h>
#⁠include <stdlib.h>
#⁠include <string.h>

#⁠ifdef WINDOWS
#⁠define NM_EXPORT __declspec(dllexport)
#⁠define NM_IMPORT __declspec(dllimport)
#⁠else
#⁠define NM_EXPORT
#⁠define NM_IMPORT
#⁠define FBUDF_API
#⁠endif

NM_IMPORT void* ib_util_malloc(long);

#⁠define MAX(a, b) (a > b) ? a : b
#⁠define MIN(a, b) (a < b) ? a : b

const int nm_int64_digit_count = 21;
const int nm_UUID_char_count = 16;
typedef long long int NM_SIZE;
typedef long long int NM_COUNT;

NM_EXPORT void testof_dsc_sub_type(paramdsc* param, paramdsc* result);

#⁠ifdef __cplusplus
}
#⁠endif

#⁠endif /* FBUDF_H */

script.sql ===================================

connect 'd:\database\my_database.fdb' user 'SYSDBA' password 'masterkey';
drop database;
create database 'd:\database\my_database.fdb' user 'SYSDBA' password 'masterkey' page_size 8192 default character set UTF8;
set term ^;

declare external function test_of_dsc_sub_type
integer by descriptor
, varchar(255) by descriptor
returns
parameter 2
entry_point 'testof_dsc_sub_type' module_name 'fb_udf_test' ^

select test_of_dsc_sub_type(0), test_of_dsc_sub_type(4) from RDB$DATABASE ^

commit work ^
set term ;^

result ======================================

C:\WINDOWS\system32>"C:\Program Files (x86)\Firebird\Firebird_3_0\isql" -i D:\source\NOTEMATRIX\FBSQL\test\script.sql
Use CONNECT or CREATE DATABASE to specify a database

TEST_OF_DSC_SUB_TYPE TEST_OF_DSC_SUB_TYPE
================================== ====================================================
the quick brown fox jumps over the lazy dog The quick b

@firebird-automations
Copy link
Collaborator Author

Commented by: @asfernandes

Why are you returning CHAR (dtype_text) instead of VARCHAR (dtype_varying), if the metadata declares VARCHAR?

@firebird-automations
Copy link
Collaborator Author

Commented by: Segey Khalyutin (notesoft)

dtype_text is easy to use and I`m expected on firebird typcast mechanism

Realy, we`a prepared structure like paramdsc in java client application, convert any cursors data in one BLOB (like len:value;len:value;... structure), put in DB by stored procedure and extract individual cursor.record.field data from BLOB by UDF... We are implement this mechanism for transmit any relation cursors data by long-ping intranet and replicate logical group of cursors data,,,

I`m corrected bug example.
With dtype_varying dsc_sub_type work correct.
But with dtype_text truncate 1/4

=====================

#⁠include "main.h"

int main(int argc, char** argv)
{
return (EXIT_SUCCESS);
}

const int varchar\_indicator\_size = sizeof\(ISC\_USHORT\);
typedef ISC\_USHORT fb\_len;
const int max\_varchar\_size = 65535 \- varchar\_indicator\_size; // in theory

struct vvary
\{
        fb\_len		vary\_length;
        ISC\_UCHAR	vary\_string\[max\_varchar\_size\];
\};

inline void set\_varchar\_len\(ISC\_UCHAR\* vchar, const fb\_len len\)
\{
        reinterpret\_cast<vvary\*\>\(vchar\)\-\>vary\_length = len;
\}

/*

declare external function test_of_dsc_sub_type
integer by descriptor
, varchar(255) by descriptor
returns
parameter 2
entry_point 'testof_dsc_sub_type' module_name 'fb_udf_test'

*/

NM\_EXPORT void testof\_dsc\_sub\_type\(paramdsc\* param, paramdsc\* result\)
\{        
  	ISC\_LONG val = \*\(\(ISC\_LONG\*\)\(param\-\>dsc\_address\)\);
           
    short      charset = val == 4 ? 4 : 0;
    short    collation = val == 4 ? 4 : 0;        
    const char\*  value = val == 4 ? "The quick brown fox jumps over the lazy dog\."
                                  : "the quick brown fox jumps over the lazy dog";
    int            len = strlen\(value\);                
                    
    result\-\>dsc\_dtype    = dtype\_text;
    result\-\>dsc\_scale    = 0;
    result\-\>dsc\_length   = len; 
    result\-\>dsc\_sub\_type = \(short\)\(\(collation\) << 8 \| \(charset\)\); 
    result\-\>dsc\_flags    = 0;
    result\-\>dsc\_address  = \(ISC\_UCHAR\*\)value;
\}

/**
declare external function test_of_dsc_sub_type_var
integer by descriptor
, char(255) by descriptor
returns
parameter 2
entry_point 'testof_dsc_sub_type_var' module_name 'fb_udf_test' ^
*/

NM\_EXPORT void testof\_dsc\_sub\_type\_var\(paramdsc\* param, paramdsc\* result\)
\{        
  	ISC\_LONG val = \*\(\(ISC\_LONG\*\)\(param\-\>dsc\_address\)\);
           
    short      charset = val == 4 ? 4 : 0;
    short    collation = val == 4 ? 4 : 0;        
    const char\*  value = val == 4 ? "The quick brown fox jumps over the lazy dog\."
                                  : "the quick brown fox jumps over the lazy dog";
    int            len = strlen\(value\);                
                    
    result\-\>dsc\_dtype    = dtype\_varying;
    result\-\>dsc\_scale    = 0;
    result\-\>dsc\_length   = len \+ varchar\_indicator\_size; 
    result\-\>dsc\_sub\_type = \(short\)\(\(collation\) << 8 \| \(charset\)\); 
    result\-\>dsc\_flags    = 0;
           
    set\_varchar\_len\(result\-\>dsc\_address, len\);

   	memcpy\(result\-\>dsc\_address \+ varchar\_indicator\_size, value, len\); 
\}

==========================

connect 'd:\database\my_database.fdb' user 'SYSDBA' password 'masterkey';
-- drop user MY_USER;
drop database;
create database 'd:\database\my_database.fdb' user 'SYSDBA' password 'masterkey' page_size 8192 default character set UTF8;
-- create user MY_USER password 'MY_PASS' ;
set term ^;

declare external function test_of_dsc_sub_type
integer by descriptor
, char(255) by descriptor
returns
parameter 2
entry_point 'testof_dsc_sub_type' module_name 'fb_udf_test' ^

declare external function test_of_dsc_sub_type_var
integer by descriptor
, varchar(255) by descriptor
returns
parameter 2
entry_point 'testof_dsc_sub_type_var' module_name 'fb_udf_test' ^

select test_of_dsc_sub_type(0), test_of_dsc_sub_type(4) from RDB$DATABASE ^
select test_of_dsc_sub_type_var(0), test_of_dsc_sub_type_var(4) from RDB$DATABASE ^

========================================

:\WINDOWS\system32>"C:\Program Files (x86)\Firebird\Firebird_3_0\isql" -i D:\source\NOTEMATRIX\FBSQL\test\script.sql
Use CONNECT or CREATE DATABASE to specify a database

TEST_OF_DSC_SUB_TYPE TEST_OF_DSC_SUB_TYPE
=============================================================================== ===============================================================================
the quick brown fox jumps over the lazy dog The quick b

TEST_OF_DSC_SUB_TYPE_VAR TEST_OF_DSC_SUB_TYPE_VAR
=============================================================================== ===============================================================================
the quick brown fox jumps over the lazy dog The quick brown fox jumps over the lazy dog.

@firebird-automations
Copy link
Collaborator Author

Modified by: Segey Khalyutin (notesoft)

priority: Trivial [ 5 ] => Major [ 3 ]

@firebird-automations
Copy link
Collaborator Author

Modified by: Segey Khalyutin (notesoft)

summary: return by descriptor UDF varchar parametr trunc for 1/4 of it`s len if UDF set paramdsc->dsc_sub_type to UTF8 => return by descriptor UDF char parametr trunc for 1/4 of it`s len if UDF set paramdsc->dsc_sub_type to UTF8

@firebird-automations
Copy link
Collaborator Author

Commented by: Segey Khalyutin (notesoft)

On WIN WI-T4.0.0.1434 Firebird 4.0 Beta 1 x64 error reproduce too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant