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

show-stopper bug in pgsql_prepare() #91

Closed
GitMensch opened this issue Jul 22, 2022 · 9 comments
Closed

show-stopper bug in pgsql_prepare() #91

GitMensch opened this issue Jul 22, 2022 · 9 comments
Labels
bug Something isn't working

Comments

@GitMensch
Copy link
Contributor

GitMensch commented Jul 22, 2022

This function eats any quotation -

std::string pgsql_prepare(const std::string& sql)
{
int n = 1;
std::vector<std::string> items;
std::vector<std::string> out_items;
split_in_args(items, sql, true);
for (auto item : items) {
if (starts_with(item, "\"") || item.back() == '\'') {
out_items.push_back(item);
continue;
}
size_t pos = item.find('?');
if (pos == std::string::npos) {
out_items.push_back(item);
continue;
}
std::string s;
for (auto c : item) {
if (c == '?')
s += ("$" + std::to_string(n++));
else
s += c;
}
out_items.push_back(s);
}
return vector_join(out_items, ' ');
}

Input: SET APPLICATION_NAME TO "Identifier1 Identifier2 Identifier3"
Output: SET APPLICATION_NAME TO Identifier1 Identifier2 Identifer3
Result from DB:

ERROR: syntax error at or near "Identifier2"
LINE 1: SET APPLICATION_NAME TO Identifer1 Identifier2 Identife...

Workaround for this specific statement: SET APPLICATION_NAME TO "Identifier1-Identifier2-Identifier3", but that's unlikely to be possible in every other case (and not that easy to look for in the complete code).

@mridoni
Copy link
Owner

mridoni commented Jul 22, 2022

Yes, that's the problem with the string constants I was talking about in #21 (comment), I am working on it.

Thanks

@mridoni
Copy link
Owner

mridoni commented Jul 24, 2022

This should now be fixed in the internal repository, this

      EXEC SQL
      SET APPLICATION_NAME TO "Identifier1 Identifier2 Identifier3"
      END-EXEC.

is emitted as:

GIXSQL 01  SQ0002.
GIXSQL     02  FILLER PIC X(0061) VALUE "SET APPLICATION_NAME TO ""Ide"
GIXSQL  &  "ntifier1 Identifier2 Identifier3""".
GIXSQL     02  FILLER PIC X(1) VALUE X"00".

@GitMensch
Copy link
Contributor Author

Thank you for the update. Should I try to test with the current version or is a bugfix version that includes #88 and maybe even VARCHAR2 likely until mid of next week (I'm on a longer vacation afterwards)?

@mridoni
Copy link
Owner

mridoni commented Jul 24, 2022

I don’t think I can manage a “full” release, a pre-release containing only the updated source and an autoconf-enabled tarball is more likely (but not sure). I already made a few modifications for #88 (letting “smart” cursor init be the default) but I could not reproduce your problem (my test cases pass but there is obviously something missing); a minimal test case, if you have time, might help.

The new EXEC SQL VAR stuff could also be coming in the same timeframe and pre-release (still: if possible, not 100% sure) but since it touches a core part of the runtime, I am a little afraid of regressions, so I will have to see how it behaves.

Thanks.

mridoni added a commit that referenced this issue Jul 27, 2022
- Solved a problem in #91 (string constants with single/double quotes are now parsed and emitted correctly)
- Solved a problem in #88 ("smart" cursor initialization is now performed correctly)
@GitMensch
Copy link
Contributor Author

Looks like you've fixed a different issue here - in the compiler.
My case - with the referenced code, which is unchaged in 1.0.18dev1 - is still broken: dynamic prepared statements with a stack trace of

#0  pgsql_prepare (...) at libgixsql-pgsql/DbInterfacePGSQL.cpp:260
#1  DbInterfacePGSQL::prepare (...) at libgixsql-pgsql/DbInterfacePGSQL.cpp:297
#2  GIXSQLPrepareStatement (...) at libgixsql/gixsql.cpp:928

Sample from above: the prepared statement variable in COBOL contains:
SET APPLICATION_NAME TO "Identifier1 Identifier2 Identifier3" (there was a workaround of replacing spaces to underscores here)

Sample 2 (which there is no workaround for):
SELECT MAX(VAL) FROM TAB WHERE TABART NOT IN ('AAAAA ' ,'BBBBBB ' ,'CCCCCCCC' ,'DDDD ' ,'EEEEEEEE' )

and an even more strange output from pgsql_prepare:

SELECT MAX(VAL) FROM TAB WHERE TABART NOT IN ('AAAAA ' , BBBBB ' , CCCCCCC' ,'DDDD ' , EEEEEEE' )

@GitMensch GitMensch changed the title show-stopper bug in pgsql_prepare show-stopper bug in pgsql_prepare() Jul 29, 2022
@GitMensch
Copy link
Contributor Author

GitMensch commented Jul 29, 2022

Quick Hack - which possibly chrashes something else and most likely dynamic parameters:

-	std::string prepared_sql = pgsql_prepare(sql);
+	std::string prepared_sql = std::string(sql);

possibly could improved to still support dynamic parameters with some "if find '?' ... but fixing pgsql_prepare would be the correct thing in any case.

@mridoni
Copy link
Owner

mridoni commented Jul 29, 2022

Looks like you've fixed a different issue here - in the compiler.

You are right, I will check this.

@mridoni mridoni added the bug Something isn't working label Jul 30, 2022
@mridoni
Copy link
Owner

mridoni commented Aug 2, 2022

I rewrote pgsql_prepare, this is fixed in the internal repository. BTW: this function just transforms all anonymous parameter placeholders into numbered ones, as PostgreSQL requires. It adds some minimal "cross-platform behaviour" (e.g. you don't need to modify the prepared statements when going from ODBC to PostgreSQL) but it could be removed if deemed unnecessary.

std::string pgsql_prepare(const std::string& sql)
{
	int n = 1;
	bool in_single_quoted_string = false;
	bool in_double_quoted_string = false;
	std::string out_sql;

	for (auto itc = sql.begin(); itc != sql.end(); ++itc) {
		char c = *itc;

		switch (c) {
			case '"':
				out_sql += c;
				in_double_quoted_string = !in_double_quoted_string;
				continue;

			case '\'':
				out_sql += c;
				in_single_quoted_string = !in_single_quoted_string;
				continue;

			case '?':
				if (!in_single_quoted_string && !in_double_quoted_string)
					out_sql += ("$" + std::to_string(n++));
				else 
					out_sql += c;
				continue;

			default:
				out_sql += c;

		}
	}
	
	return out_sql;
}

@mridoni mridoni added the ready label Aug 2, 2022
mridoni added a commit that referenced this issue Aug 15, 2022
This is a maintenance pre-release for GixSQL. It fixes a few issues and adds two new databases drivers (Oracle and SQLite). The next "standard" release (presumably v1.0.18) will have feature parity for all database drivers.

- Added new Oracle driver, based on ODPI
- Added new SQLite driver
- Solution for "PG: issue with prepared statements" (#99)
- Solution for "PCursors cannot be re-opened after close" (#98)
- Solution for "libgixpp: setStatus is called for errors without DBI parm passed - sets SQLERRM" (#94)
- Solution for "error handling (especially for 07001)" (#92)
- Solution for "show-stopper bug in pgsql_prepare" (#91)
- Solution for "PREPARE does not work with VARLENGTH groups (ocesql compat)" (#79)
- Partial solution for "PREPARE does not work with VARLENGTH groups (ocesql compat)" (#68)
- Solution for "The PostgreSQL driver needs START TRANSACTION before using cursors" (#14)
- Solution for "FR: support EXEC SQL VAR" (#21)
- Fixed a bug in "problems with "codegen / logic issue for "GIXSQLCursorDeclareParams" (#88)
- Fixed COMP-3 handling in drivers other than PostgreSQL
- Rewrote the test suite (still MSTest-based) to dynamically generate a matrix of test to be run on the various platforms/database drivers
mridoni added a commit that referenced this issue Aug 23, 2022
- Added new Oracle driver, based on ODPI
- Added new SQLite driver
- All the drivers have been updated and now implement the complete set of supported features
- Solution for "PG: issue with prepared statements" (#99)
- Solution for "PCursors cannot be re-opened after close" (#98)
- Solution for "libgixpp: setStatus is called for errors without DBI parm passed - sets SQLERRM" (#94)
- Solution for "error handling (especially for 07001)" (#92)
- Solution for "show-stopper bug in pgsql_prepare" (#91)
- Solution for "PREPARE does not work with VARLENGTH groups (ocesql compat)" (#79)
- Partial solution for "PREPARE does not work with VARLENGTH groups (ocesql compat)" (#68)
- Solution for "The PostgreSQL driver needs START TRANSACTION before using cursors" (#14)
- Solution for "FR: support EXEC SQL VAR" (#21)
- Fixed a bug in "problems with "codegen / logic issue for "GIXSQLCursorDeclareParams" (#88)
- Solution for "FR: allow mapping of "NoRecCode"' (#95) - added --no-rec-code parameter to gixpp
- Tokens in the parser have been labeled to improve diagnostics (pulled PR #96 by @GitMensch)
- Fixed COMP-3 handling in drivers other than PostgreSQL
- Rewrote the test suite (still MSTest-based) to dynamically generate a matrix of test to be run on the various platforms/database drivers
- Added options for parameter generation in gixpp (-a was removed)
- Added new GIXSQL_FIXUP_PARAMS option for runtime, to automatically convert parameter format in prepared statments
- "Native" cursors are now the default for the PostgreSQL driver
- "Smart" cursor initialization is now the default for all cursors, including those declared in WORKING-STORAGE (-L was removed from gixpp), should fix #101
- Removed dynamic cursor emulation from the ODBC driver when using PostgreSQL
@mridoni mridoni removed the ready label Aug 24, 2022
@GitMensch
Copy link
Contributor Author

That looks to be fixed, so closing.

Halbaroth added a commit to Halbaroth/gixsql that referenced this issue Oct 17, 2024
The tests #000 and mridoni#91 always fail. This commit disables them
temporary.
Halbaroth added a commit to OCamlPro/gixsql that referenced this issue Oct 17, 2024
Disable two tests

The tests #000 and mridoni#91 always fail. This commit disables them
temporary.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants