Baffling "Invalid length parameter passed to the LEFT or SUBSTRING function" - tsql

I have a very simple query, as such:
SELECT * FROM production.LINE_JOB_QUEUE WHERE L_ROWID = 33 ORDER BY SEQNO
When I try to run it using ADO.NET, I get the following error:
System.Data.SqlClient.SqlException (0x80131904): Invalid length parameter passed to the LEFT or SUBSTRING function.
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning()
at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
at System.Data.SqlClient.SqlDataReader.HasMoreRows()
at System.Data.SqlClient.SqlDataReader.ReadInternal(Boolean setTimeout)
at System.Data.SqlClient.SqlDataReader.Read()
at System.Data.Common.DataAdapter.FillLoadDataRow(SchemaMapping mapping)
at System.Data.Common.DataAdapter.FillFromReader(DataSet dataset, DataTable datatable, String srcTable, DataReaderContainer dataReader, Int32 startRecord, Int32 maxRecords, DataColumn parentChapterColumn, Object parentChapterValue)
at System.Data.Common.DataAdapter.Fill(DataTable[] dataTables, IDataReader dataReader, Int32 startRecord, Int32 maxRecords)
at System.Data.Common.LoadAdapter.FillFromReader(DataTable[] dataTables, IDataReader dataReader, Int32 startRecord, Int32 maxRecords)
at System.Data.DataTable.Load(IDataReader reader, LoadOption loadOption, FillErrorEventHandler errorHandler)
at System.Data.DataTable.Load(IDataReader reader, LoadOption loadOption)
at Temporal.DBO.Definitions.DBBroker`3.ExecuteDT(String SQL, Int32 TimeoutSeconds) in C:\Users\Aaron\Documents\Development\Framework v.4\Temporal Libraries\Temporal.DBO\Definitions\DbBroker.vb:line 81
Thing is, as you can see above, my query contains neither LEFT nor SUBSTRING. The view which is being queried (production.LINE_JOB_QUEUE) is does not contain them either, and is comprised only of tables (no other views) and none of these tables have calculated columns using either of those function either.
The view's code is such:
ALTER VIEW [production].[LINE_JOB_QUEUE] AS
SELECT
l.ROWID as L_ROWID, l.code, q.rowid Q_ROWID, r.rowid as R_ROWID,
L.NAME AS QUEUENAME, P.SKU AS ITEMNO, P.NAME AS DESCR,
Q.lotno, q.orderqty, q.SEQNO,q.ONEOFF,l.IsUp, l.IsLocked,l.IsPortOpen,r.IsHeld,
case
when isnull(q.ACTIVE,0) = 1 then 'ACTIVE' -- active: 0=inactive; 1=active
when r.canceldate IS not null then 'CANCELLED'
when r.enddate IS not null then 'COMPLETED'
else 'PENDING'
end as STATUS, q.proddate, qa.itemno as cur_itemno,qa.name as cur_descr,
isnull(ra.lineisactive,0)lineisactive, isnull(q.ACTIVE,0) q_active,
r.startdate, r.enddate,
case
when r.startdate is null then null
else system.udfTimeSpanFromSeconds(DATEDIFF(SECOND, R.STARTDATE, ISNULL(R.ENDDATE, GETDATE())))
end AS ELAPSED
FROM catalog.PRODUCTS P, production.Queue Q
left join production.RUN r on q.rowid = r.rowid,
production.LINES L
left join
(select q.lineid, q.itemno, p.name
from production.queue q, catalog.products p
where p.sku = q.itemno and q.active = 1 ) QA on qa.lineid = L.rowid
left join (select lineid,max( cast(active as integer) ) as lineisactive
from production.RUN group by lineid ) RA on ra.lineid = l.rowid
where l.rowid = q.lineid and
P.SKU = q.ITEMNO
While I get the above error when running the query in ADO.NET, I can run the same query in SSMS, and it runs perfectly fine, with no exceptions, every single time.
I saw one posting online, where someone had the same problem because the log file location had run out of space, and freeing up space solved the problem for them. However in our case, the log file location has 133 GB free space, so that is not the issue. But just to be thorough, I shrunk the database and logs. No help. I have tried restarting the Sql Server instance, no luck. I have also tried rebooting the server, all with no luck.
The database server is Sql Server 2008 R2, running on a Windows Server 2008 SP2 machine.
The app is a .NET 4 website running in IIS6 on a Windows Server 2003 R2 machine.
Any help greatly appreciated. Thanks!

Reposted comment as answer:
is udfTimeSpanFromSeconds a function you have defined? I suspect you have SUBSTRING or LEFT in that, and that the reason it doesn't fail in SSMS but via your code is due to the differences in date/time format sent to the query.

Related

Errors with declared array/table variable values in SAP HanaDB SQL

I am trying to add a declared variable to replace a hardcoded list of values in a "where in" clause.
Researching how Hana handles array variables it seems like I can do this by declaring an array and then either using a select directly on it or by unnesting it first into a table but I keep getting errors I can't resolve.
When I try it this way:
DO
BEGIN
DECLARE CODES_ARRAY NVARCHAR(100) ARRAY = ARRAY('01','02','03','04');
SELECT T0."ItemCode"
FROM OITM T0
INNER JOIN OITW T1 ON T0."ItemCode" = T1."ItemCode"
WHERE "WhsCode" IN (SELECT "code" FROM :CODES_ARRAY); -- line 9 where error occurs
END;
I get this error message sql syntax error: incorrect syntax near ")": line 9 col 54 (at pos 239)
I can't figure out what the syntax error resolution is.
So then I tried inserting a declared table variable like this:
DO
BEGIN
DECLARE CODES_ARRAY NVARCHAR(100) ARRAY = ARRAY('01','02','03','04');
DECLARE CODES_TABLE TABLE = UNNEST(:CODES_ARRAY) AS ("code"); -- line 5 where error occurs
SELECT T0."ItemCode"
FROM OITM T0
INNER JOIN OITW T1 ON T0."ItemCode" = T1."ItemCode"
WHERE "WhsCode" IN (SELECT "code" FROM CODES_TABLE); -- I know : is missing here but when adding, the same error from previous block shows up
END;
and I get this error message: identifier must be declared: 1: line 5 col 38 (at pos 123)
As far as I can tell the array variable is declared as it should be so I don't know how to resolve the error.
I've read the SAP Hana SQL Reference documentation (for array/table variables, unnest function, etc.) over and over and it seems like I've got everything setup correctly but can't figure out these errors. I would like to be able to use both of these approaches at different times if possible (the "array variable to table variable" and the "array variable only" approaches)
I don't know exactly what is going on here, but one thing I notice that the two different error messages referenced in my post (see difference from errors in the first two code blocks) is that each error is occurring either immediately before the use of the variable with the : (in the case of the UNNEST) or immediately following the variable with the : (in the case of using in the SELECT * FROM in the query).
Because of that, I wondered if the issue is "upstream" at the Hana ADO.NET application query preparation and execution call level, but I ran a test and when I double checked the query string just before it is executed, it appears unchanged and the variables with : still look as they should, so at least as far as just before execution through Hana ADO.NET HanaCommand it looks correct - but once executing the query using HanaDataReader or HanaDataAdapter it returns the error messages referred to above. It may be a red herring to chase the problem from the Hana ADO.NET level but don't know what else to do.
Update
To further troubleshoot, I tried executing this code block below using hdbsql.exe -n XXX.XXX.XXX.XXX:30015 -u XXX -p XXX -m -I "c:\temp\test.sql" -c "#" and it works! So, the errors I see only show up when executing the same query through the Hana ADO.NET interface.
DO
BEGIN
DECLARE CODES_ARRAY NVARCHAR(10) ARRAY = ARRAY('01','02','03','04');
DECLARE CODES_TABLE TABLE ("code" NVARCHAR(10)) = UNNEST(:CODES_ARRAY) AS ("code");
SELECT T0."ItemCode"
FROM OITM T0
INNER JOIN OITW T1 ON T0."ItemCode" = T1."ItemCode"
WHERE "WhsCode" IN (SELECT "code" FROM :CODES_TABLE); -- line 10 where error occurs when using Hana ADO.NET
END;
#
The above fails when through Hana ADO.NET with the error message: sql syntax error: incorrect syntax near ")": line 10 col 54 (at pos 325) but works when executed through hdbsql.
Update
The C# code that executes the query is fairly straight forward, but for completeness of troubleshooting effort I am including the interesting parts of our HanaHelper class. This code works successfully to execute 100s of queries a day without errors or problems. This is the first time where a variable of any type has been attempted to be declared or used in a query through this code and when the errors started showing up. As far as I can tell, the issue is tied to the use of the : when using the variable in the query.
public class HanaHelper
{
public HanaConnection objConn = null;
public HanaHelper(string ConnectionString)
{
try
{
objConn = new HanaConnection(ConnectionString);
}
catch (Exception e)
{
Console.WriteLine(#"Exception thrown by HanaConnection: {0}\n{1}", e.Message, e.InnerException);
}
}
public DataSet GetData(string strSQL)
{
using (HanaCommand objCmd = new HanaCommand(strSQL, objConn))
{
using (HanaDataAdapter objDA = new HanaDataAdapter(objCmd))
{
DataSet objDS = new DataSet();
try
{
objDA.Fill(objDS);
}
catch (Exception)
{
throw;
}
finally
{
// do something interesting regardless of success or failure
}
objConn.Close();
return objDS;
}
}
}
}
Any clue here why the same query works through hdbsql but fails when executing through Hana ADO.NET?
Update
I figured out how to use HanaSQLTrace in the C# code so that I can inspect the prepared query text and viola, the source of error messages becomes apparent, all occurrences of ":VARNAME" are replaced with "? " (a ? replaces the : and a space for each character in the variable name). I suppose it is trying to pre-substitute occurrences of : with a ? as if there were parameters to be substituted.
How can this behavior be disabled, or worked with, or worked around so that I can use variables in a query in Hana ADO.NET effectively?
Updated based on the OP feedback.
To refer to a variable (in order to access its value(s)) in SQLScript it's
necessary to put a colon : in front of the variable name.
The main issue, however, turns out to be the declaration of the CODES_TABLE table variable.
With HANA 2 SPS 4 the error message is
`SAP DBTech JDBC: [264]: invalid datatype: unknown type SYSTEM.TABLE: line 5 col 23`
This points to the declaration of the TABLE typed variable CODES_TABLE which lacks the definition of what columns should be in the table.
Adding this fixes the issue.
With these changes, your code should work:
DO
BEGIN
DECLARE CODES_ARRAY NVARCHAR(100) ARRAY = ARRAY('01','02','03','04');
DECLARE CODES_TABLE TABLE ("code" NVARCHAR(100)) = UNNEST(:CODES_ARRAY) AS ("code");
-- ^^^^^^^^^^^^^^^^^^^^^^
-- |
---------------------------------------+
SELECT
T0."ItemCode"
FROM
OITM T0
INNER JOIN OITW T1
ON T0."ItemCode" = T1."ItemCode"
WHERE
"WhsCode" IN (SELECT "code" FROM :CODES_TABLE);
-- ^
-- |
---------------------------------------+
END;
An alternative option to declare and assign the table variable is to not use the DECLARE command.
DO
BEGIN
DECLARE CODES_ARRAY NVARCHAR(100) ARRAY = ARRAY('01','02','03','04');
CODES_TABLE = UNNEST(:CODES_ARRAY) AS ("code");
SELECT
T0."ItemCode"
FROM
OITM T0
INNER JOIN OITW T1
ON T0."ItemCode" = T1."ItemCode"
WHERE
"WhsCode" IN (SELECT "code" FROM :CODES_TABLE);
END;

How to change Postgres JDBC driver properties to change return class on count function?

I am running a Jasper report (via an jrxml), I am connecting / reading from a Postgres database.
The Sql returns a value from a count function, this then causes java.lang.ClassCastException when writing this value to the Jasper report (via an xml), can I amend the JDBC driver properties to handle this (rather than amend the sql).
The line in the SQL that caused the error was
COALESCE(B.GP_COUNT,0) as GP_COUNT
If I amend the line that populates GP_COUNT using a CAST statement then this works OK in the xml:-
CAST(COUNT(DISTINCT PD_CDE) AS INT4) AS GP_COUNT
I am looking for a solution that avoids changes to the xml’s & jrxml’s (as we have hundreds of reports to convert to Postgres from DB2)
Any help appreciated, I am not a java person so I apologise in advance.
The PostgreSQL JDBC Driver does not return a string, but a BIGINT as result of the count aggregate function.
This Java code:
Class.forName("org.postgresql.Driver");
java.sql.Connection conn = java.sql.DriverManager.getConnection(
"jdbc:postgresql://127.0.0.1/mydb?user=myuser"
);
java.sql.Statement stmt = conn.createStatement();
java.sql.ResultSet rs = stmt.executeQuery("SELECT count(*) FROM pg_class");
System.out.println("Type of count(*) is a BIGINT: "
+ (rs.getMetaData().getColumnType(1) == java.sql.Types.BIGINT)
);
rs.close();
stmt.close();
conn.close();
produces:
Type of count(*) is a BIGINT: true

Throw error in SQL Server 2008 R2

I'm working with SQL Server 2008 R2 and I have an stored procedure where I'm trying to throw errror
throw 50001, 'Couldnot process,Please verify Transaction ID and EmbossLine', 1
But the query doesn't get executed and throws error on 50001. It was working fine on SQL Server 2012. I think there is some issue with versions. Is there anyother way I can throw error in SQL Server 2008 R2?
This is my stored procedure:
Alter procedure [dbo].[spGetRedemption]
#pan varchar(19),
#transId bigint
AS
Begin
if EXISTS(select * from POS_Transactions where ID=#transId)
Begin
select
PT.ID, PT.TransactionDate, M.MerchantName1,
PT.TerminalID, PT.BatchNumber, PT.SequenceNumber, PT.PAN,
C.EmbossName, PT.TotalAmount, PT.CurrencyCode,
TT.TransactionType, PT.InvoiceNumber
from
POS_Transactions PT
inner join
Terminal T on T.TerminalID = PT.TerminalID
inner join
Merchant M on M.MerchantID = T.MerchantID
inner join
Card C on C.EmbossLine = PT.PAN
inner join
TransactionType TT on TT.TransactionTypeID = PT.TransactionTypeID
where
PT.ID = #transId
and PT.PAN = #pan
END
Else
Begin
throw 50001, 'Couldnot process,Please verify Transaction ID and EmbossLine', 1
END
End
Throw is not available in SQL Server 2008R2; it was first introduced in SQL Server 2012.
https://msdn.microsoft.com/en-us/library/ee677615(v=sql.110).aspx
The alternative would be to use Raiserror (note; only 1 E in the middle; it's not RaiseError).
From the above link, there are some differences between these methods:
RAISERROR statement
If a msg_id is passed to RAISERROR, the ID must be defined in sys.messages.
The msg_str parameter can contain printf formatting styles.
The severity parameter specifies the severity of the exception.
THROW statement
The error_number parameter does not have to be defined in sys.messages.
The message parameter does not accept printf style formatting.
There is no severity parameter. The exception severity is always set to 16.

Entity Framework Takes a longer time to get the response the first time using within the same context

I am having an issues with the EF that the first query takes a long time. I thought the query itself was taking a long time. So, I used
context.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);
to see what query is being sent. It only took only 1 ms but from the open connection to close connection, it took 18 second. The following is the message from the debug message.
**Opened connection at 3/19/2015 9:25:49 PM +06:30
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[ItemId] AS [ItemId],
[Extent1].[SerialNumber] AS [SerialNumber],
[Extent1].[SimNumber] AS [SimNumber],
[Extent1].[ItemStatusId] AS [ItemStatusId],
[Extent1].[StoreId] AS [StoreId]
FROM [dbo].[ItemDetail] AS [Extent1]
-- Executing at 3/19/2015 9:25:49 PM +06:30
-- Completed in 1 ms with result: SqlDataReader
Closed connection at 3/19/2015 9:26:07 PM +06:30**
Within the same context, another query similar to the previous one was sent. It only took 1 second from the Open to Close connection.
**Opened connection at 3/19/2015 9:26:10 PM +06:30
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[ItemId] AS [ItemId],
[Extent1].[SerialNumber] AS [SerialNumber],
[Extent1].[SimNumber] AS [SimNumber],
[Extent1].[ItemStatusId] AS [ItemStatusId],
[Extent1].[StoreId] AS [StoreId]
FROM [dbo].[ItemDetail] AS [Extent1]
INNER JOIN [dbo].[Item] AS [Extent2] ON [Extent1].[ItemId] = [Extent2].[Id]
WHERE ([Extent1].[ItemStatusId] = #p__linq__0) AND ([Extent2].[CategoryId] = #p__linq__1) AND ([Extent1].[StoreId] = #p__linq__2)
-- p__linq__0: '1' (Type = Int32, IsNullable = false)
-- p__linq__1: '2' (Type = Int32, IsNullable = false)
-- p__linq__2: '1' (Type = Int32, IsNullable = false)
-- Executing at 3/19/2015 9:26:10 PM +06:30
-- Completed in 1 ms with result: SqlDataReader
Closed connection at 3/19/2015 9:26:11 PM +06:30**
Why does the first query take longer time to close the connection?
I know that the first query usually take time because of loading the meta data. But this is different that the open connection and executing query are so close and after getting the results, it takes a long time to close the connection in the first query.
Without knowing more details of your code, the only factor I can come up with is that it matters how a LINQ query is processed. One thing in particular that can cause a connection to remain open relatively long is enumerating a LINQ query and executing some time-consuming process in each iteration:
var details = from d in ItemDetail
where ...
select new { ... }
foreach (var detail in details)
{
// DbDataReader reads a record on each iteration
SomeLengthyProcess(detail);
}
// Connection is closed after the last iteration.
Here's a sample output (leaving out some irrelevant details)
Opened connection at 09:48:33
SELECT statement
-- Executing at 09:48:33
-- Completed in 14 ms with result: SqlDataReader
Record1
Record2
Record3
Record4
Record5
Closed connection at 09:48:37
Which shows that the statement itself is executed in "no time", but that it takes another 4s for the reader to produce each record.
The way to make the connection close sooner is:
foreach (var detail in details.ToList())
which builds an in-memory list first and then iterates over it. In this case, the connection closes immediately after the "Completed" logging line.

JDBC setDate not working with preparedstatement

I am pretty new to Java JDBC. I am trying to create a JDBC preparedstatement to do a SELECT between two Oracle DATE values.
I know that data exists between these two times, as I can do the query directly.
When I execute the prepared statement from within my JDBC code, however, it returns 0 rows.
My input start and times are Long Unix time values in milliseconds.
I have tried to pare down the code to the bare minimum:
public static List<Oam1731Sam5Data> getData(Long startTime, Long endTime) {
try {
String query = "SELECT timecaptured from oam1731data5 " +
"WHERE timecaptured between ? and ?";
pstmt = conn.prepareStatement(query); // create a statement
Date javaStartDate = new Date(startTime);
Date javaEndDate = new Date(endTime);
pstmt.setDate(1, javaStartDate);
pstmt.setDate(2, javaEndDate);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
String serviceId = rs.getString("SERVICEID");
String recordSource = rs.getString("RECORDSOURCE");
Date timeCaptured = rs.getDate("TIMECAPTURED");
Long oneWayMaxDelay = rs.getLong("ONEWAYMAXDELAY");
Long twoWayMaxDelay = rs.getLong("TWOWAYMAXDELAY");
Long twoWayMaxDelayVar = rs.getLong("TWOWAYMAXDELAYVAR");
Long packetLoss = rs.getLong("PACKETLOSS");
}
} catch (SQLException se) {
System.err.println("ERROR: caught SQL exception, code: " + se.getErrorCode() +
", message: " + se.getMessage());
}
The issue is that this returns 0 rows, where the same query returns data:
select insert_date, recordsource, serviceid, timecaptured, onewaymaxdelay, twowaymaxdelay, twowaymaxdelayvar, packetloss from oam1731data5
where timecaptured between to_date('2012-01-18 07:00:00','YYYY-MM-DD HH24:MI:SS')
and to_date('2012-01-18 08:00:00','YYYY-MM-DD HH24:MI:SS')
order by insert_date
DBMS_OUTPUT:
INSERT_DATE RECORDSOURCE SERVICEID TIMECAPTURED ONEWAYMAXDELAY TWOWAYMAXDELAY TWOWAYMAXDELAYVAR PACKETLOSS
1/18/2012 10:43:36 AM EV TAMP20-MTRO-NID1SYRC01-MTRO-NID1 1/18/2012 7:25:24 AM 40822 79693 343 0
1/18/2012 10:43:36 AM EV SYRC01-MTRO-NID1TAMP20-MTRO-NID1 1/18/2012 7:25:13 AM 39642 79720 334 0
1/18/2012 10:43:36 AM EV TAMP20-MTRO-NID1SYRC01-MTRO-NID1 1/18/2012
I have seen and ready many posts about problems somewhat like this, but have not been
able to find the key yet!
I thought about trying to make my query use a string and simply convert my dates to strings to be able to insert them for the Oracle TO_DATE function, but it seems like I should not have to do this.
And here is the output from my println statements. Is it an issue that the dates that print do NOT show the time portion?
SQL query: SELECT timecaptured from oam1731data5 WHERE timecaptured between ? and ?
Java Oracle date: 2012-01-18 end date 2012-01-18
Thanks in advance for any help.
Mitch
A java.sql.Date represents a date without time. You must use a Timestamp if you care about the time part.
The javadoc of java.sql.Date says:
To conform with the definition of SQL DATE, the millisecond values
wrapped by a java.sql.Date instance must be 'normalized' by setting
the hours, minutes, seconds, and milliseconds to zero in the
particular time zone with which the instance is associated.
Using Date for your start and end dates shouldn't cause any problem. The data in the specified interval should be retrieved in that time interval (Those data that you printed which were inserted on 1/18/2012 are supposed to be retrieved in this case.) Therefore I don't think that omitting time portion is your problem.