row number 0 is out of range 0..-1 LIBPQ - c++

query = "select * results where id = '";
query.append(ID);
query.append("'");
res = PQexec(conn, query.c_str());
After executing this statement, i get the following error.
row number 0 is out of range 0..-1
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_construct null not valid
However, when I run the same query in postgresql, it does not have any problem.
select * from results where id = 'hello'
The only problem is that if the query parameter passed is not in database, it would throw runtime error. If you provide the exact query parameter which is in database, it executes normally.

That's two separate errors, not one. This error:
row number 0 is out of range 0..-1
is from libpq, but is reported by code you have not shown here.
The error:
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_construct null not valid
is not from PostgreSQL, it is from your C++ runtime.
It isn't possible for me to tell exactly where it came from. You should really run the program under a debugger to tell that. But if I had to guess, based on the code shown, I'd say that ID is null, so:
query.append(ID);
is therefore aborting the program.
Separately, your code is showing a very insecure practice where you compose SQL by string concatenation. This makes SQL injection exploits easy.
Imagine what would happen if your "ID" variable was set to ';DROP TABLE results;-- by a malicious user.
Do not insert user-supplied values into SQL by appending strings.
Instead, use bind parameters via PQexecParams. It looks complicated, but most parameters are optional for simple uses. A version for your query, assuming that ID is a non-null std::string, would look like:
PGresult res;
const char * values[1];
values[0] = ID.c_str();
res = PQexecParams("SELECT * FROM results WHERE id = $1",
1, NULL, values, NULL, NULL, 0);
If you need to handle nulls you need another parameter; see the documentation.

Maybe, a bit too late but just want to put in my 5 cents.
Got this error also these days with a very simple stored procedure of the kind like:
CREATE OR REPLACE FUNCTION selectMsgCounter()
RETURNS text AS
$BODY$
DECLARE
msgCnt text;
BEGIN
msgCnt:= (SELECT max(messageID)::text from messages);
RETURN 'messageCounter: ' || msgCnt;
END
$BODY$
LANGUAGE plpgsql STABLE;
Made some debugging with:
if (PQntuples(res)>=1)
{
char* char_result=(char*) realloc(NULL,PQgetlength(res, 0,0)*sizeof(char));
strcpy( char_result,PQgetvalue(res, 0, 0));
bool ok=true;
messageCounter=QString(char_result).remove("messageCounter: ").toULongLong(&ok);
if (!ok) messageCounter=-1;
qDebug()<<"messageCounter: " << messageCounter;
free(char_result);
PQclear(res);
PQfinish(myConn); // or do call destructor later?
myConn=NULL;
}
else
{
fprintf(stderr, "storedProcGetMsgCounter Connection Error: %s",
PQerrorMessage(myConn));
PQclear(res);
PQfinish(myConn); // or do call destructor later?
myConn=NULL;
}
Turned out that the owner of the stored procedure was not the one whose credentials I used to log in with.
So - at least - in my case this error "row number 0 is out of range 0..-1" was at first sight a false positive.

Related

ORA-01722 Error when Returning Identity Column into variable

I have the table below, and I am inserting a record into it. For some reason, the RETURNING [column_name] INTO [variable] is throwing an ORA-01722: invalid number error. I've looked at other similar issues on stack overflow and elsewhere and only thing I found is someone was using a variable for the [column_name] that needed an extra step, but i'm using the [column_name] explicitly.
TABLE:
catalog_year
catalog_year_id number (pk, identity column)
catalog_year varchar2(10)
catalog_status_id number
declare
l_new_calendar_year_id number;
begin
insert into catalog_year
(catalog_year, catalog_status_id)
values
('2022-2023', 5)
returning catalog_year_id into l_new_calendar_year_id;
end;

SQLite 3 Error when using parameter string, but not when implicitly typed

I have a snippet of code from my python 2.7 program:
cur.execute("UPDATE echo SET ? = ? WHERE ID = ?", (cur_class, fdate, ID,))
that when run, keeps throwing the following error:
sqlite3.OperationalError: near "?": syntax error
The program is supposed to insert today's date, into the class column that matches the student ID supplied. If I remove the first "?" like so and hard code the parameter:
cur.execute("UPDATE echo SET math = ? WHERE ID = ?", (fdate, ID,))
everything works just fine. I've googled all over the place and haven't found anything that works yet so I'm throwing out a lifeline.
I've tried single quotes, double quotes, with and without parenthesis and a few other things I can't remember now. So far nothing works other than hard coding that first parameter which is really inconvenient.
As a troubleshooting step I had my program print the type() of each of the variables and they're all strings. The data type of the the cur_class field is VARCHAR, fdate is DATE, and ID is VARCHAR.
Thanks to the tip from #Shawn earlier I solved the issue with the following code and it works great:
sqlcommand = "UPDATE echo SET " + cur_class + " = " + fdate + " WHERE ID = " + ID
cur.execute(sqlcommand)
This way python does the heavy lifting and constructs my string with all the variables expanded, then has the db execute the properly formatted SQL command.

CTE with HierarchyID suddenly causes parse error

So I have this self-referencing table in my database named Nodes, used for storing the tree structure of an organization:
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](max) NULL,
[ParentId] [int] NULL,
(+ other metadata columns)
And from it I'm using HIERARCHYID to manage queries based on access levels and such. I wrote a table-valued function for this, tvf_OrgNodes, a long time ago, tested and working on SQL Server 2008 through 2014 and it's remained unchanged since then since it's been doing great. Now, however, something has changed because the parsing of HIERARCHYIDs from path nvarchars ("/2/10/8/") results in the following error, matching only 4 hits (!) on Google:
Msg 6522, Level 16, State 2, Line 26
A .NET Framework error occurred during execution of user-defined routine or aggregate "hierarchyid":
Microsoft.SqlServer.Types.HierarchyIdException: 24000: SqlHierarchyId operation failed because HierarchyId object was constructed from an invalid binary string.
When altering the function to only return NVARCHAR instead of actual HIERARCHYID's, the paths all look fine, beginning with / for the root, followed by /2/ etc etc. Simply selecting HIERARCHYID::Parse('path') also works fine. I actually got the function working by leaving the paths as strings all the way until the INSERT into the function result, parsing the paths there. But alas, I get the same error when I then try and insert the reusulting data into a table of same schema.
So the question is, Is this a bug, or does anybody know of any (new?) pitfalls in working with HIERARCHYIDs<->Path strings that could cause this? I don't get where the whole binary string idea comes from.
This is the code of the TVF:
CREATE FUNCTION [dbo].[tvf_OrgNodes] ()
RETURNS #OrgNodes TABLE (
OrgNode HIERARCHYID,
NodeId INT,
OrgLevel INT,
ParentNodeId INT
) AS
BEGIN
WITH orgTree(OrgNode, NodeId, OrgLevel, ParentNodeId) AS (
-- Anchor expression = root node
SELECT
CAST(HIERARCHYID::GetRoot() AS varchar(180))
, n.Id
, 0
, NULL
FROM Nodes n
WHERE ParentId IS NULL -- Top level
UNION ALL
-- Recursive expression = organization tree
SELECT
CAST(orgTree.OrgNode + CAST(n.Id AS VARCHAR(180)) + N'/' AS VARCHAR(180))
, n.Id
, orgTree.OrgLevel + 1
, n.ParentId
FROM Nodes AS n
JOIN orgTree
ON n.ParentId = orgTree.NodeId
)
INSERT INTO #OrgNodes
SELECT
HIERARCHYID::Parse(OrgNode),
NodeId,
OrgLevel,
ParentNodeId
FROM orgTree;
RETURN;
END
I might have recently installed .NET 4.53 aka 4.6 for the lolz. Can't find much proof of it anywhere except in the reg, though: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft.NETFramework\v4.0.30319\SKUs.NETFramework,Version=v4.5.3

ODBC error "String data, right truncation State code: 22001" with SQL Server database

I have a test table using a Microsoft SQL Server that is defined like this:
CREATE TABLE [dbo].[Table] (
[FirstName] NVARCHAR (255) NULL,
[LastName] NVARCHAR (255) NULL
);
There's just one row in the table with the values "person" and "man", respectively.
I'm trying to add a function that will update the values of that row but I keep running into this "[Microsoft][ODBC SQL Server Driver]String data, right truncation State code: 22001" error and I cannot figure out what the problem is. I've looked around and people say that it is caused by the data being too long to fit in the column but that's impossible because the string I'm trying to update with is only two characters, and as you can see in the table definition there is plenty of space for it.
I'm using a prepared statement for optimization purposes and the code creating it looks something like this:
const tString query("UPDATE \"" + tableName + "\" SET " + setClause + " WHERE " + whereClause + ";");
SQLHSTMT statement;
SQLAllocHandle(SQL_HANDLE_STMT, fSQLConnection, &statement);
SQLPrepareW(statement, (SQLWCHAR *) query.mWideStr(), SQL_NTS);`
The query string looks like this:
UPDATE "Table" SET "FirstName" = ?, "LastName" = ? WHERE "FirstName" = ? AND "LastName" = ?;
And then I am binding the parameters like this:
// We have our own string class that we use, which is where the mWideStr() and mGetStrSize()
// come from. mWideStr() returns a pointer to a UCS-2 buffer and mGetStrSize() returns the
// size in bytes.
SQLLEN pcbValue(SQL_NTS);
SQLUSMALLINT paramIndex(1);
// Call this for each parameter in the correct order they need to be bound, incrementing the
// index each time.
SQLBindParameter(statement, paramIndex++, SQL_PARAM_INPUT, SQL_C_WCHAR, SQL_VARCHAR, 255, 0, (SQLPOINTER) paramValue.mWideStr(), paramValue.mGetStrSize(), &pcbValue);
The first and second bound parameters are the new values which are both just "55", then third would be "person" and fourth would be "man".
Then to execute the statements it's just a call to SQLExecute():
SQLExecute(statement);
The call to SQLExecute() fails and then the error is generated and there is some more code that outputs the error message. As far as I can tell this should all be working perfectly fine. I have another database using Oracle that uses the exact same setup and code and it works without any issues, it's just SQL Server that's barfing for some reason. Is there something obviously wrong here that I'm missing? Does SQL Server have some weird rules that I need to add somewhere?
The SQLLEN pcbValue(SQL_NTS); variable being passed to SQLBindParameter() was going out of scope between binding the parameters and executing the statement, which means that some garbage data was being pointed to in the parameter binding. I also realized that you don't need to specify the last parameter. You can just pass NULL and it will act as if it is a nul-terminated string.
So the fix was to remove the SQLLEN pcbValue(SQL_NTS); variable and to just pass NULL to SQLBindParameter() for the last parameter instead.
Stupid mistake, but worth noting I suppose.

SubSonic3 SetExpression problem

Next SubSonic3 query gives me an error:
Db.Update<Tag>()
.SetExpression("Popularity")
.EqualTo("Popularity+1")
.Where<Tag>(x => x.TagId == tagId)
.Execute();
Error: failed: System.FormatException : Failed to convert parameter value from a String to a Int32.
The sql that is generated is ok, but the collection of parameters contains two parameters that need to be set.
UPDATE [Tagging].[Tag]
SET Popularity=Popularity+1
WHERE [Tagging].[Tag].[TagId] = #0
One of the parameters set #up_Popularity to 'Popularity+1'. Since this is the first parameter being set, sql triese to assign this string 'Popularity+1' to an integer.
Is this a bug or am I doing something wrong?
Db.Update<Tag>()
.SetExpression("Popularity = Popularity + 1")
.Where<Tag>(x => x.TagId == tagId)
.Execute();
This should work ... but I think it's for wholesale updates. Not sure. Your best bet is to use our CodingHorror:
new CodingHorror("UPDATE Tags SET Popularity = Popularity + 1 WHERE #1",
tagId).Execute();
I'd be amazed if that was supposed to work. When I need to have a string evaluated as part of the SQL (and not by SubSonic) I almost always end up having to use a CodingHorror.
However, you should be able to do this by using a separate query. Something like:
Db.Update<Tag>()
.Set("Popularity")
.EqualTo(Tag.SingleOrDefault(t => t.TagId == tagId).Popularity + 1)
.Where<Tag>(x => x.TagId == tagId)
.Execute();