Getting maximum string length exeeded error when inserting a CLOB in HANA (longer than 7FFFFF) - hana

We are trying to insert a large string into a table column and getting an error "length can't exceed maximum length(8388607 bytes)". (0x7F FFFF). The input data field length exceeds 10MB.
HANA version SPS 9 (Rev 97)
Data type of variable and table column is CLOB
Using INSERT in a SQLSCRIPT Stored Procedure
The HANA data types documentation say that maximum length of any LOB object is 2GB (0x7FFF FFFF). Our string length is well within this limit. So this is very confounding. Will appreciate any hints to resolve this.
Thanks a lot.
---------- CODE
CREATE PROCEDURE XXX_SCHEMA.PROC_INSERT_INTO_CLOB
( IN DATA_CLOB CLOB, )
BEGIN
LANGUAGE SQLSCRIPT SQL SECURITY INVOKER default schema XXX_SCHEMA AS
INSERT INTO "XXX_SCHEMA"."XXX::DB_YY_CLOB"
(
'ABC' ,
CURRENT_TIMESTAMP ,
DATA_CLOB
)
SELECT F1,
F2,
:DATA_CLOB
FROM DUMMY ;
END;
-- Table Defintion
table.schemaName = "XXX_SCHEMA";
table.tableType = ROWSTORE;
table.columns = [
{name = "F1";sqlType = NVARCHAR;nullable = false; length = 3;},
{name = "F2";sqlType = TIMESTAMP;nullable = true;},
{name = "DATA_CLOB";sqlType = CLOB;nullable = true;}];

The reason for the error is that you seem to use string methods to deal with the CLOB data.
When I tried simple things like inserting a really long value generated via
update rclob set data_clob = lpad ('X', 2000000000, 'Y');
I also received the error message
Could not execute 'update rclob set data_clob = lpad ('X', 2000000000, 'Y')'
SAP DBTech JDBC: [384]: string is too long: length can't exceed maximum length(8388607bytes) at function lpad() (at pos 29)
Since LPAD produces a string before it gets entered into the CLOB, the error message is thrown before the CLOB column is actually touched.
Generally LOB columns can only be inserted by binding the data to a parameter in the insert statement.

Related

Conversion failed when converting the nvarchar value to data type int sql server

I have a table. There is data in this table and there is a checkbox next to each data. Multiple selection is possible. After the user makes a selection, the id numbers of the selected columns are come in the array. I convert the array to string and send it to the stored procedure and I run the following stored procedure:
Example value for #ResultsIds: 65, 66, 67, 68, 125
#ResultsIds nvarchar(250)
UPDATE MyTable SET [IsVerified] = 1 WHERE Id IN (#ResultsIds)
And I got this error:
Conversion failed when converting the nvarchar value '65, 66, 67, 68, 125' to data type int. Because [Id] column is int data type.
I tried CAST and CONVERT functions of SQL but it didn't work.
SQL Server doesn't do that automatically. Assuming you're on a recent version, you can do this:
declare #ResultsIds nvarchar(250) = '65,66,67,68,125'
UPDATE MyTable
SET [IsVerified] = 1
WHERE Id IN (
select [value]
from string_split(#ResultIDs, ',')
)
declare #ResultsIds nvarchar(250)='65,66,67,68,125'
UPDATE MyTable SET [IsVerified] = 1 WHERE cast(Id as varchar) IN (#ResultsIds)
I solved problem using foreach. I separated the numbers in the string from commas and transferred each number to the array. Then I updated the array one by one by running foreach loop.
public void Verify(DB db, string rows)
{
int[] nums = Array.ConvertAll(rows.Split(','), int.Parse);
foreach (int value in nums)
{
DbCommand cmd = db.GetStoredProcCommand("VerifyProcess");
db.AddInParameter(cmd, "#ResultId", DbType.Int32, value);
db.ExecuteNonQuery(cmd);
}
}

Passing char value to function

I have the following function:
CREATE OR REPLACE FUNCTION BANINST1."F_COC_AUTO_AWARD_FILTER" (pidm number) return number
as
return_field number;
cursor get_pidm is
select distinct SHRDGMR.SHRDGMR_PIDM
from SATURN.SHRDGMR SHRDGMR,
SATURN.SORLCUR SORLCUR,
SATURN.SORLFOS SORLFOS,
DWSCHEMA.DAP_AUDIT_DTL#LINKDWTEST
where SORLCUR.SORLCUR_PIDM = SHRDGMR.SHRDGMR_PIDM
and SORLFOS.SORLFOS_PIDM = SORLCUR.SORLCUR_PIDM
and SORLCUR.SORLCUR_LEVL_CODE = SHRDGMR.SHRDGMR_LEVL_CODE
and SORLCUR.SORLCUR_DEGC_CODE = SHRDGMR.SHRDGMR_DEGC_CODE
and SORLFOS.SORLFOS_TERM_CODE = SORLCUR.SORLCUR_TERM_CODE
and SHRDGMR.SHRDGMR_PIDM = pidm
and SHRDGMR.SHRDGMR_DEGS_CODE = 'AW'
and SORLCUR.SORLCUR_PROGRAM in ('STCC', 'CC')
and DWSCHEMA.DAP_AUDIT_DTL.DAP_DEGREE in ('CPCC-CDS', 'CC1-CDS', 'CC2-CDS')
and SORLFOS.SORLFOS_MAJR_CODE <> DWSCHEMA.DAP_AUDIT_DTL.DAP_AUD_VALUE2
and trim(DWSCHEMA.DAP_AUDIT_DTL.DAP_STU_ID) = (select spriden_id from spriden where spriden_pidm = pidm and spriden_change_ind is null);
begin
open get_pidm;
fetch get_pidm into return_field;
close get_pidm;
return return_field;
end;
/
This is the call to the function from a where clause:
baninst1.f_coc_auto_award_filter#test(RAD_PRIMARY_MST.RAD_USER_DEF1) is not null
The function accepts a number data type parameter.
The passed column RAD_PRIMARY_MST.RAD_USER_DEF1 is a char(12) data type that has a value such as 293858.
The following error is returned when calling the function: ORA-01722: invalid number
I have tried to pass a number value to the function in several different ways:
baninst1.f_coc_auto_award_filter#test(to_number(trim(RAD_PRIMARY_MST.RAD_USER_DEF1))) is not null
baninst1.f_coc_auto_award_filter#test(cast(RAD_PRIMARY_MST.RAD_USER_DEF1 as number(8))) is not null
All attempts return the same error ORA-01722: invalid number
If I hard-code the D_PRIMARY_MST.RAD_USER_DEF1 value to a number, the function call works.
baninst1.f_coc_auto_award_filter#test(293858) is not null
How do I pass the char value from RAD_PRIMARY_MST.RAD_USER_DEF1 to the function?
This might be the keyword:
such as 293858
Are you sure that there aren't any non-numeric values in that column? With that datatype (char), there's always doubt. If you are storing numbers in there, why isn't it number?
This query should return invalid values which cause your code to break.
select * from d_primary_mst where not regexp_like(rad_user_def1, '^\d+$')
Also, if you are passing a string, why do you force the function to accept a number? Why don't you
CREATE OR REPLACE FUNCTION BANINST1.F_COC_AUTO_AWARD_FILTER
(pidm RAD_PRIMARY_MST.RAD_USER_DEF1%type)
return SHRDGMR.SHRDGMR_PIDM%type
as
return_field SHRDGMR.SHRDGMR_PIDM%type;
cursor get_pidm is
select distinct SHRDGMR.SHRDGMR_PIDM ...
By the way, get rid of double quotes when creating Oracle objects; they only cause problems.

String operation in SQL to reverse a string

In DB2 9.7 I am looking for a way to reverse a string in a SQL query.
I am familiar with SQL Server where the query would be like
SELECT
REVERSE(LEFT_TO_REIGHT) AS RIGHT_TO_LEFT
FROM
TABLE1;
I couldn't find a similar function in DB2. is there a simple way to reverse a string?
Creating a REVERSE(..) function is unnecessary.
DB2 has something called RIGHT(string-expression, length):
The RIGHT function returns the rightmost string of string-expression
of length length, expressed in the specified string unit. If
string-expression is a character string, the result is a character
string. If string-expression is a graphic string, the result is a
graphic string
So if you're interested in the last 8 characters, you can pretty trivially do this via:
SELECT RIGHT(left_to_right, 8) AS right_to_left
FROM Table1
(I'm actually still concerned about the fact that you're splitting off 8 characters consistently, as it implies you have a multi-part key of some sort).
Try something like:
SELECT STRIP(CAST( TRANSLATE('87654321',LEFT_TO_REIGHT, '12345678') AS VARCHAR(8) ))
FROM TABLE1;
Due to the original question this is the first webpage that comes up when one searches for 'How to reverse a string in DB2'.
Here is an answer that doesn't require implementing it in C and shouldn't brake on non-pure-Engilsh strings regardless of their length.
Be warned though, the efficiency is 'meh' at best.
CREATE FUNCTION REVERSE_STRING(STR VARCHAR(100))
RETURNS VARCHAR(100)
LANGUAGE SQL
SPECIFIC REVERSE_STRING
DETERMINISTIC
REVERSE: BEGIN
DECLARE REVERSED_STRING VARCHAR(100);
DECLARE REVERSED_CHARACTERS_INDEX INTEGER;
SET REVERSED_STRING='';
SET REVERSED_CHARACTERS_INDEX=0;
WHILE (REVERSED_CHARACTERS_INDEX < CHARACTER_LENGTH(STR, CODEUNITS16))
DO
SET REVERSED_CHARACTERS_INDEX = REVERSED_CHARACTERS_INDEX + 1;
SET REVERSED_STRING = CONCAT(
REVERSED_STRING,
LEFT(RIGHT(STR, REVERSED_CHARACTERS_INDEX, CODEUNITS16), 1, CODEUNITS16));
END WHILE;
RETURN REVERSED_STRING;
END REVERSE#
The idea is to get a substring which starts from the n-th character from the right till the end of the string, then take the first element of this substring from the left and append it to a reversed string. This operation is conducted n times where n is the length of a string to be reversed.
You can use it like any other function.
SELECT FIRSTNME AS FIRSTNAME, REVERSE_STRING(FIRSTNME) AS REVERSED_FIRSTNAME
FROM SAMPLE.EMPLOYEE#
Example output
Answering the original question of reversing a string there's user defined functions published on the IBM site that will do it that you can find here. There's apparently no built in ability in DB2
https://www.ibm.com/developerworks/community/blogs/SQLTips4DB2LUW/entry/reverse?lang=en
Tortured SQL version:
CREATE OR REPLACE FUNCTION REVERSE(INSTR VARCHAR(4000))
RETURNS VARCHAR(4000) SPECIFIC REVERSE
DETERMINISTIC NO EXTERNAL ACTION CONTAINS SQL
RETURN WITH rec(pos, res) AS (VALUES (1, CAST('' AS VARCHAR(4000)))
UNION ALL
SELECT pos + 1, SUBSTR(INSTR, pos , 1) || res
FROM rec
WHERE pos <= LENGTH(INSTR)
AND pos < 5000)
SELECT res FROM rec WHERE pos > LENGTH(INSTR);
But then you have to do this as well, yuck:
CREATE BUFFERPOOL bp32 PAGESIZE 32K;
CREATE SYSTEM TEMPORARY TABLESPACE tsp32 PAGESIZE 32K BUFFERPOOL bp32;
A saner C implementation
#include <sqludf.h>
#ifdef __cplusplus
extern "C"
#endif
void SQL_API_FN ReverseSBCP(SQLUDF_VARCHAR *inVarchar,
SQLUDF_VARCHAR *outVarchar,
SQLUDF_SMALLINT *inVarcharNullInd,
SQLUDF_SMALLINT *outVarcharNullInd,
SQLUDF_TRAIL_ARGS)
{
int inLen, inPos, outPos;
if (*inVarcharNullInd == -1)
{
*outVarcharNullInd = -1;
}
else
{
inLen = strlen(inVarchar);
for (inPos = 0, outPos = inLen -1; inPos < inLen; inPos++, outPos--)
{
outVarchar[outPos] = inVarchar[inPos];
}
outVarchar[inLen] = '\0';
*outVarcharNullInd = 0;
}
return;
}

Using newline character and adding several rows of strings into one

I have in my hands an old app on informix server and I'm migrating data into a different database. Both are informix databases. I have a particular problem with one table. Old app used it to support multiline text.
OldTable:
HeaderID int
LineNum int
Descr nvarchar(50,1)
NewTable:
HeaderID int
Descr lvarchar(max)
So, for each HeaderID I have to read the descriptions ordered by line number and put them all together for insert into a new table. There has to be a newline character between each line for conversion to succeed.
Any tips on how to do this?
If you need to do it from SQL then you can use procedure:
CREATE FUNCTION get_text(aHeaderID int)
RETURNING lvarchar;
DEFINE result lvarchar;
DEFINE vcfld lvarchar;
LET result=NULL;
EXECUTE PROCEDURE IFX_ALLOW_NEWLINE('T');
FOREACH cur1
FOR SELECT Descr INTO vcfld FROM OldTable WHERE HeaderID = aHeaderID ORDER BY LineNum
IF result IS NULL THEN
LET result = vcfld;
ELSE
LET result = result || '
' || vcfld;
END IF;
END FOREACH;
RETURN result;
END FUNCTION;
(notice usage of IFX_ALLOW_NEWLINE and line breaking when updating result)
Then you can fill NewTable using:
UPDATE NewTable SET Descr=get_text(HeaderID);
You can use PreparedStatement. This is example in Jython that uses JDBC Informix driver:
db = DriverManager.getConnection(db_url, usr, passwd)
pstm = db.prepareStatement("SELECT vc FROM src ORDER BY id")
rs = pstm.executeQuery()
lines = []
while (rs.next()):
lines.append(rs.getString(1))
pstm = db.prepareStatement("INSERT INTO dest (lvc) VALUES (?)")
pstm.setString(1, '\n'.join(lines))
rs = pstm.execute()
db.close()

Calling a stored procedure in SQL Server to get a unicode string

I'm trying to get a name by calling a stored procedure.
sql code:
create procedure GetName
#ID int,
#name nvarchar(32) output
as
select #name=name from SalesInfo where ID=#ID
c code
...
SQLRETURN rc;
SQLLEN cbParam = SQL_NTS;
int ID = 1;
wchar_t name[32];
rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &ID, 0, NULL);
rc = SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT_OUTPUT, SQL_C_WCHAR, SQL_WCHAR, SQL_DESC_LENGTH, 0, name, sizeof(name), &cbParam);
rc = SQLExecDirect(hstmt, TEXT("{call GetName(?,?)}"), SQL_NTS);
I received a string, but there was an error message, 'string data, right truncation'
The string was padded with blanks, like "name "
you need to increase the size of your nvarchar() so that it doesn't truncate the strings that are larger than 32
increase the size of wchar_t name[N];and #name nvarchar(N) output
Well to get rid of the trim simply use RTRIM(col) AS [col], to determin what length of char vars you need then LEN(Originalcol) or DATALENGTH(Originalcol) http://msdn.microsoft.com/en-us/library/ms173486.aspx in your case to create a proc to see waht actual length you are getting and what you need to define. As its a single var, you wont get much a hit by using NVARCHAR(MAX)