Zeos 7.2.6 + Oracle - set schema on TZConnection?

The forum for ZeosLib 7.2 Report problems. Ask for help, post proposals for the new version and Zeoslib 7.2 features here. This is a forum that will be edited once the 7.2.x version goes into RC/stable!!

My personal intention for 7.2 is to speed up the internals as optimal a possible for all IDE's. Hope you can help?! Have fun with testing 7.2
User avatar
aehimself
Zeos Dev Team
Zeos Dev Team
Posts: 766
Joined: 18.11.2018, 17:37
Location: Hungary

Zeos 7.2.6 + Oracle - set schema on TZConnection?

Post by aehimself »

Hello,

I have an application connecting to an Oracle database with multiple schemas, containing the same table names. I dynamically create a TZQuery and try to execute a simple command:
INSERT INTO TABLE (COLUMN) VALUES ('ColumnValue')

This fails with an error message (cancelled by the user I think...). SQLMonitor shows that it's because TZQuery attempted to update a table with the same name, but in a different schema that I'd like. No surprise, if I change the query to
INSERT INTO SCHEMA.TABLE (COLUMN) VALUES ('ColumnValue')

everything works fine.

There is a Schema property on TZSQLMetaData; is there anything like this on a TZConnection / TZQuery so it keeps everything using it within it's boundaries?

Thanks!
Delphi 12.1, Zeos 8 from latest GIT snapshot
Using:
- MySQL server 8.0.18; libmariadb.dll 3.3.8
- Oracle server 11.2.0, 12.1.0, 19.0.0; oci.dll 21.13
- MSSQL 2012, 2019; sybdb.dll FreeTDS_2435
- SQLite 3.45.2
marsupilami
Platinum Boarder
Platinum Boarder
Posts: 1918
Joined: 17.01.2011, 14:17

Re: Zeos 7.2.6 + Oracle - set schema on TZConnection?

Post by marsupilami »

The connection has a catalog property. Usually that one should do the trick. For a query I would expect that the automatically generated SQL is generated using schema names. It seems it is not?
User avatar
aehimself
Zeos Dev Team
Zeos Dev Team
Posts: 766
Joined: 18.11.2018, 17:37
Location: Hungary

Re: Zeos 7.2.6 + Oracle - set schema on TZConnection?

Post by aehimself »

And you were right, as ever :) Setting the "Catalog" property to the schema name forced the queries using that connection to the right table.

The thing which confused me was that it's called Schema in the Metadata and was not brave enough to experiment.

@ Jan, I really owe you a beer now.
Delphi 12.1, Zeos 8 from latest GIT snapshot
Using:
- MySQL server 8.0.18; libmariadb.dll 3.3.8
- Oracle server 11.2.0, 12.1.0, 19.0.0; oci.dll 21.13
- MSSQL 2012, 2019; sybdb.dll FreeTDS_2435
- SQLite 3.45.2
marsupilami
Platinum Boarder
Platinum Boarder
Posts: 1918
Joined: 17.01.2011, 14:17

Re: Zeos 7.2.6 + Oracle - set schema on TZConnection?

Post by marsupilami »

aehimself wrote:And you were right, as ever :) Setting the "Catalog" property to the schema name forced the queries using that connection to the right table.
Good to know. :)
aehimself wrote:The thing which confused me was that it's called Schema in the Metadata and was not brave enough to experiment.
Hmmm - the problem for me is that different vendors seem to have different opionions on what a schema and what a catalog is. *Sigh* - we need docs that tell everybody how Zeos works...
User avatar
aehimself
Zeos Dev Team
Zeos Dev Team
Posts: 766
Joined: 18.11.2018, 17:37
Location: Hungary

Re: Zeos 7.2.6 + Oracle - set schema on TZConnection?

Post by aehimself »

marsupilami wrote:the problem for me is that different vendors seem to have different opionions on what a schema and what a catalog is
This is exactly what I started to wonder about - and the deeper you dig, the worse it gets :)
Delphi 12.1, Zeos 8 from latest GIT snapshot
Using:
- MySQL server 8.0.18; libmariadb.dll 3.3.8
- Oracle server 11.2.0, 12.1.0, 19.0.0; oci.dll 21.13
- MSSQL 2012, 2019; sybdb.dll FreeTDS_2435
- SQLite 3.45.2
User avatar
aehimself
Zeos Dev Team
Zeos Dev Team
Posts: 766
Joined: 18.11.2018, 17:37
Location: Hungary

Re: Zeos 7.2.6 + Oracle - set schema on TZConnection?

Post by aehimself »

So... bump. Unfortunately it seems that it does not work - always. Now using 7.3 latest snapshot, when I did a

Code: Select all

ZQuery.Edit;
ZQuery.FieldByName('xxx').AsBytes := bb;
ZQuery.Post;
I get a "0 records updated" exception. I investigated a little bit and it turns out that the statement generator is simply trying to figure out the schema and is inserting the first available maybe; but not considering what is set on the ZConnection.

Same thing happens when I executed a SELECT query:

Code: Select all

[2019.12.10 18:43:00.602] SQL trace: '2019-12-10 18:12:00' cat: Prepare, proto: oracle, msg: Statement 3 : SELECT FIELD1, FIELD2, FIELD3 FROM MYTABLE
[2019.12.10 18:43:00.635] SQL trace: '2019-12-10 18:12:00' cat: Execute prepared, proto: oracle, msg: Statement 3
[2019.12.10 18:44:37.902] SQL trace: '2019-12-10 18:12:37' cat: Prepare, proto: oracle, msg: Statement 4 : SELECT ALL_TAB_COLUMNS.OWNER, ALL_TAB_COLUMNS.TABLE_NAME, ALL_TAB_COLUMNS.COLUMN_NAME, ALL_TAB_COLUMNS.DATA_TYPE, ALL_TAB_COLUMNS.DATA_LENGTH, ALL_TAB_COLUMNS.DATA_PRECISION, ALL_TAB_COLUMNS.DATA_SCALE, ALL_TAB_COLUMNS.NULLABLE, ALL_TAB_COLUMNS.DATA_DEFAULT, ALL_TAB_COLUMNS.COLUMN_ID, ALL_COL_COMMENTS.COMMENTS FROM ALL_TAB_COLUMNS JOIN ALL_COL_COMMENTS ON ALL_COL_COMMENTS.TABLE_NAME = ALL_TAB_COLUMNS.TABLE_NAME AND ALL_COL_COMMENTS.COLUMN_NAME = ALL_TAB_COLUMNS.COLUMN_NAME AND ALL_COL_COMMENTS.OWNER = ALL_TAB_COLUMNS.OWNER  WHERE ALL_TAB_COLUMNS.TABLE_NAME like 'MYTABLE' ORDER BY ALL_TAB_COLUMNS.COLUMN_ID
[2019.12.10 18:44:37.989] SQL trace: '2019-12-10 18:12:37' cat: Execute prepared, proto: oracle, msg: Statement 4
If you execute the metadata fetch query Zeos is executing, you'll quickly see that it does not filter for a schema at all; it returns all columns in all schemas for the table MYTABLE.

I don't know if it works the same way in other drivers, but in TZOracleDatabaseMetadata.UncachedGetColumns the SchemaPattern variably is empty (thus no schema filtering); and that's because TZAbstractResultSetMetadata.LoadColumns is tying to get schema name from the SQL command. It simply doesn't seem to care what is requested on the TZConnection :(

Edit: The same thing seems to be the reason for why posting a query succeeds with a query like "SELECT FIELD FROM TABLE" but fails with "SELECT * FROM TABLE" (EZDatabaseError was raised with the message Cannot update a complex query with more then one table). TZGenericCachedResolver.DefineTableName finds the table in all schemas, and it can not choose which to choose from. Exception is raised here:

Code: Select all

      else if (Result <> '') and (Temp <> '') and (Temp <> Result) then
        raise EZSQLException.Create(SCanNotUpdateComplexQuery);
(where Result is the table name to use and Temp is the next possible table name returned from ALL SCHEMAS from Metadata)
Delphi 12.1, Zeos 8 from latest GIT snapshot
Using:
- MySQL server 8.0.18; libmariadb.dll 3.3.8
- Oracle server 11.2.0, 12.1.0, 19.0.0; oci.dll 21.13
- MSSQL 2012, 2019; sybdb.dll FreeTDS_2435
- SQLite 3.45.2
Fr0sT
Zeos Dev Team
Zeos Dev Team
Posts: 280
Joined: 08.05.2014, 12:08

Re: Zeos 7.2.6 + Oracle - set schema on TZConnection?

Post by Fr0sT »

I'm not familiar with Oracle but shouldn't Schema be rather a prop of a dataset than of a connection? Connection could access several schemas or am I missing something?
User avatar
aehimself
Zeos Dev Team
Zeos Dev Team
Posts: 766
Joined: 18.11.2018, 17:37
Location: Hungary

Re: Zeos 7.2.6 + Oracle - set schema on TZConnection?

Post by aehimself »

Well, yes and no. For me it makes sense that a connection is "bound" to a schema and it does not let anything to go out of it; but again - in this case it should. In a real world scenario (especially if we consider network layer / RDBMS protocol) you are right - an established TCP tunnel can transport data to and from all schemas the connection has access to; the query will decide which schema it manipulates.

Unfortunately though, schema can only be defined on TZMetaData (& TZConnection) but not on TZAbstractRODataSet.
Delphi 12.1, Zeos 8 from latest GIT snapshot
Using:
- MySQL server 8.0.18; libmariadb.dll 3.3.8
- Oracle server 11.2.0, 12.1.0, 19.0.0; oci.dll 21.13
- MSSQL 2012, 2019; sybdb.dll FreeTDS_2435
- SQLite 3.45.2
marsupilami
Platinum Boarder
Platinum Boarder
Posts: 1918
Joined: 17.01.2011, 14:17

Re: Zeos 7.2.6 + Oracle - set schema on TZConnection?

Post by marsupilami »

Schema in this context is more like the default schema that is set connection wide on the server. One can change the default schema from public to some other schmea on PostgreSQL using this option. It is the same for Oracle.
User avatar
aehimself
Zeos Dev Team
Zeos Dev Team
Posts: 766
Joined: 18.11.2018, 17:37
Location: Hungary

Re: Zeos 7.2.6 + Oracle - set schema on TZConnection?

Post by aehimself »

...but alas, it doesn't seem to work :) Or at least I am missing something.
Delphi 12.1, Zeos 8 from latest GIT snapshot
Using:
- MySQL server 8.0.18; libmariadb.dll 3.3.8
- Oracle server 11.2.0, 12.1.0, 19.0.0; oci.dll 21.13
- MSSQL 2012, 2019; sybdb.dll FreeTDS_2435
- SQLite 3.45.2
marsupilami
Platinum Boarder
Platinum Boarder
Posts: 1918
Joined: 17.01.2011, 14:17

Re: Zeos 7.2.6 + Oracle - set schema on TZConnection?

Post by marsupilami »

Sorry, I didn't see this post more early..
aehimself wrote: 10.12.2019, 18:57 So... bump. Unfortunately it seems that it does not work - always. Now using 7.3 latest snapshot, when I did a

Code: Select all

ZQuery.Edit;
ZQuery.FieldByName('xxx').AsBytes := bb;
ZQuery.Post;
I get a "0 records updated" exception. I investigated a little bit and it turns out that the statement generator is simply trying to figure out the schema and is inserting the first available maybe; but not considering what is set on the ZConnection.
Unfortunately Zeos is not perfect ;) Honestly - I assume you have two tables with the same name in your databases, one living in schema A and one living in schema B? It might be that our oracle code doesn't read the metadata correctly...
aehimself wrote: 10.12.2019, 18:57 Same thing happens when I executed a SELECT query:

Code: Select all

[2019.12.10 18:43:00.602] SQL trace: '2019-12-10 18:12:00' cat: Prepare, proto: oracle, msg: Statement 3 : SELECT FIELD1, FIELD2, FIELD3 FROM MYTABLE
[2019.12.10 18:43:00.635] SQL trace: '2019-12-10 18:12:00' cat: Execute prepared, proto: oracle, msg: Statement 3
[2019.12.10 18:44:37.902] SQL trace: '2019-12-10 18:12:37' cat: Prepare, proto: oracle, msg: Statement 4 : SELECT ALL_TAB_COLUMNS.OWNER, ALL_TAB_COLUMNS.TABLE_NAME, ALL_TAB_COLUMNS.COLUMN_NAME, ALL_TAB_COLUMNS.DATA_TYPE, ALL_TAB_COLUMNS.DATA_LENGTH, ALL_TAB_COLUMNS.DATA_PRECISION, ALL_TAB_COLUMNS.DATA_SCALE, ALL_TAB_COLUMNS.NULLABLE, ALL_TAB_COLUMNS.DATA_DEFAULT, ALL_TAB_COLUMNS.COLUMN_ID, ALL_COL_COMMENTS.COMMENTS FROM ALL_TAB_COLUMNS JOIN ALL_COL_COMMENTS ON ALL_COL_COMMENTS.TABLE_NAME = ALL_TAB_COLUMNS.TABLE_NAME AND ALL_COL_COMMENTS.COLUMN_NAME = ALL_TAB_COLUMNS.COLUMN_NAME AND ALL_COL_COMMENTS.OWNER = ALL_TAB_COLUMNS.OWNER  WHERE ALL_TAB_COLUMNS.TABLE_NAME like 'MYTABLE' ORDER BY ALL_TAB_COLUMNS.COLUMN_ID
[2019.12.10 18:44:37.989] SQL trace: '2019-12-10 18:12:37' cat: Execute prepared, proto: oracle, msg: Statement 4
If you execute the metadata fetch query Zeos is executing, you'll quickly see that it does not filter for a schema at all; it returns all columns in all schemas for the table MYTABLE.
Ok - this is a bug. This is what really should happen: Upon getting a result set, the Oracle result set should try to fill in the information of TZColumnInfo. This should contain the table name - possibly including the schema. Metadata lookups may happen, if the the oracle library doesn't provide all information that is necessary. In Firebird and PostgreSQL this works very well, so we (almost) don't need to query other metadata. On other drivers your mileage may vary...
aehimself wrote: 10.12.2019, 18:57I don't know if it works the same way in other drivers, but in TZOracleDatabaseMetadata.UncachedGetColumns the SchemaPattern variably is empty (thus no schema filtering); and that's because TZAbstractResultSetMetadata.LoadColumns is tying to get schema name from the SQL command. It simply doesn't seem to care what is requested on the TZConnection :(
TZAbstractResultSetMetadata.LoadColumns is part of the loading mechanism. It is meant to be a kinda fallback mechanism to provide metadata information if the client library doesn't provide enough information.
aehimself wrote: 10.12.2019, 18:57Edit: The same thing seems to be the reason for why posting a query succeeds with a query like "SELECT FIELD FROM TABLE" but fails with "SELECT * FROM TABLE" (EZDatabaseError was raised with the message Cannot update a complex query with more then one table). TZGenericCachedResolver.DefineTableName finds the table in all schemas, and it can not choose which to choose from. Exception is raised here:

Code: Select all

      else if (Result <> '') and (Temp <> '') and (Temp <> Result) then
        raise EZSQLException.Create(SCanNotUpdateComplexQuery);
(where Result is the table name to use and Temp is the next possible table name returned from ALL SCHEMAS from Metadata)
Yes - this is the same bug.

But it looks lile we have a chance to fix this by modifying TZAbstractResultSetMetadata.LoadColumns to use the default schema name if a table has no specific schema assigned?
User avatar
aehimself
Zeos Dev Team
Zeos Dev Team
Posts: 766
Joined: 18.11.2018, 17:37
Location: Hungary

Re: Zeos 7.2.6 + Oracle - set schema on TZConnection?

Post by aehimself »

marsupilami wrote: 12.12.2019, 10:27Unfortunately Zeos is not perfect ;) Honestly - I assume you have two tables with the same name in your databases, one living in schema A and one living in schema B? It might be that our oracle code doesn't read the metadata correctly...
Yes, you are right; almost. We have about 18 schemas with same table names, because someone decided to separate test databases by schemas only :)
marsupilami wrote: 12.12.2019, 10:27TZAbstractResultSetMetadata.LoadColumns is part of the loading mechanism. It is meant to be a kinda fallback mechanism to provide metadata information if the client library doesn't provide enough information.
marsupilami wrote: 12.12.2019, 10:27But it looks lile we have a chance to fix this by modifying TZAbstractResultSetMetadata.LoadColumns to use the default schema name if a table has no specific schema assigned?
I don't think we are talking about the same thing here. There is no metadata, all information is travelling in a IZSelectSchema object, which is manually assembled by tokenizing the SQL query (probably in TZGenericStatementAnalyzer.DefineSelectSchemaFromQuery).

I don't yet have enough knowledge in Zeos to see if this is a "global" or Oracle-specific issue; also I don't really know where to put the decision logic. There's also a question on how we should detect incorrect schemas, as in my first example (0 records updates) Zeos did fill the schema name, only with an incorrect one! Unfortunately this means we can not rely on checking if it's empty.
Delphi 12.1, Zeos 8 from latest GIT snapshot
Using:
- MySQL server 8.0.18; libmariadb.dll 3.3.8
- Oracle server 11.2.0, 12.1.0, 19.0.0; oci.dll 21.13
- MSSQL 2012, 2019; sybdb.dll FreeTDS_2435
- SQLite 3.45.2
marsupilami
Platinum Boarder
Platinum Boarder
Posts: 1918
Joined: 17.01.2011, 14:17

Re: Zeos 7.2.6 + Oracle - set schema on TZConnection?

Post by marsupilami »

The TZColumnInfo objects are created in ZDbcOracleResultSet.pas in TZOracleResultSet_A.Open. There is a line in there that already sets the schema information:

Code: Select all

    ColumnInfo.SchemaName := AttributeToString(P, TempColumnNameLen);
Unfortunately it seems that only the ColumnLabel gets set there but not the ColumnName. So in a scenario like thefollowing:

Code: Select all

select ColA as ColB from SchemaC.TableD
We should know that the column label is ColB but we don't (yet?) know the original column name ColA and the original table name TableD. It seems Oracle doesn't deliver that information. This is a dilemma that Zeos tries to solve by using LoadColumns.
User avatar
aehimself
Zeos Dev Team
Zeos Dev Team
Posts: 766
Joined: 18.11.2018, 17:37
Location: Hungary

Re: Zeos 7.2.6 + Oracle - set schema on TZConnection?

Post by aehimself »

If we could make the connections default schema available to the parser, this could be solved easily there. What if we add the schema property in IZSelectSchema; and fill it in LoadColumns if it was not returned by the parser? Can we access the schema set on the connection from LoadColumns somehow?
Delphi 12.1, Zeos 8 from latest GIT snapshot
Using:
- MySQL server 8.0.18; libmariadb.dll 3.3.8
- Oracle server 11.2.0, 12.1.0, 19.0.0; oci.dll 21.13
- MSSQL 2012, 2019; sybdb.dll FreeTDS_2435
- SQLite 3.45.2
User avatar
aehimself
Zeos Dev Team
Zeos Dev Team
Posts: 766
Joined: 18.11.2018, 17:37
Location: Hungary

Re: Zeos 7.2.6 + Oracle - set schema on TZConnection?

Post by aehimself »

Sooooo... it seems I can fix it after all :) You remember the previous query? This is it now:

Code: Select all

[2019.12.13 09:05:12.097] SQL trace: '2019-12-13 09:12:12' cat: Prepare, proto: oracle, msg: Statement 3 : SELECT FIELD1, FIELD2, FIELD3 FROM MYTABLE
[2019.12.13 09:05:12.111] SQL trace: '2019-12-13 09:12:12' cat: Execute prepared, proto: oracle, msg: Statement 3
[2019.12.13 09:05:12.114] SQL trace: '2019-12-13 09:12:12' cat: Prepare, proto: oracle, msg: Statement 4 : SELECT ALL_TAB_COLUMNS.OWNER, ALL_TAB_COLUMNS.TABLE_NAME, ALL_TAB_COLUMNS.COLUMN_NAME, ALL_TAB_COLUMNS.DATA_TYPE, ALL_TAB_COLUMNS.DATA_LENGTH, ALL_TAB_COLUMNS.DATA_PRECISION, ALL_TAB_COLUMNS.DATA_SCALE, ALL_TAB_COLUMNS.NULLABLE, ALL_TAB_COLUMNS.DATA_DEFAULT, ALL_TAB_COLUMNS.COLUMN_ID, ALL_COL_COMMENTS.COMMENTS FROM ALL_TAB_COLUMNS JOIN ALL_COL_COMMENTS ON ALL_COL_COMMENTS.TABLE_NAME = ALL_TAB_COLUMNS.TABLE_NAME AND ALL_COL_COMMENTS.COLUMN_NAME = ALL_TAB_COLUMNS.COLUMN_NAME AND ALL_COL_COMMENTS.OWNER = ALL_TAB_COLUMNS.OWNER  WHERE [b]ALL_TAB_COLUMNS.OWNER = 'CONNECTIONSCHEMA' [/b]AND ALL_TAB_COLUMNS.TABLE_NAME like 'MYTABLE' ORDER BY ALL_TAB_COLUMNS.COLUMN_ID
[2019.12.13 09:05:12.969] SQL trace: '2019-12-13 09:12:12' cat: Execute prepared, proto: oracle, msg: Statement 4
I can confirm that the original code (.Edit, .FieldByName.AsBytes, .Post) also works, neither the "Cannot update complex query" is thrown when I'm editing a SELECT * FROM resultset.

I'll strip down the code a little bit and then send a pull request via Git.
Delphi 12.1, Zeos 8 from latest GIT snapshot
Using:
- MySQL server 8.0.18; libmariadb.dll 3.3.8
- Oracle server 11.2.0, 12.1.0, 19.0.0; oci.dll 21.13
- MSSQL 2012, 2019; sybdb.dll FreeTDS_2435
- SQLite 3.45.2
Post Reply