Specify and use multiple libraries in ODBC connection string - database

My odbc connection string for connecting to DB2i looks like this:
Driver={Client Access ODBC Driver (32-bit)};system=xx.xx.xx.xx;dbq=LIB1 LIB2 LIB3 LIB4 LIB5 LIB6 LIB7 LIB8;languageid=ENU;qrystglmt=-1;cmt=0;signon=1
The above connection string specifies multiple libraries/schemas for use. But when I try to access a file/table from a library other than the first one (like from LIB2...LIB8) I get a exception saying "FILE xx not found in LIB1"
Why does not it automatically search for the file/table in other specified libraries, it searches for the file in the first library only?
I need a workaround for this situation.

Use "system naming" mode, by adding naming=1 to your connection string.
In your library list, place a comma before the first library.
Driver={Client Access ODBC Driver (32-bit)};system=systemname;naming=1;
dbq=,LIB1,LIB2,LIB3,LIB4,LIB5,LIB6,LIB7,LIB8;languageid=ENU;cmt=0;signon=1

This works as documented in the manual:
The library list is used for resolving unqualified stored procedure calls and finding libraries in catalog API calls. ...
Note:
The first library listed in this property will also be the default library, which is used to resolve unqualified names in SQL statements.

As stated above, Schema/library list is used to resolve functions/procedure names, not tables.
Let assume you need to read data from lib1.tab1 and lib2.tab2;
Here my personal workarounds (from easy to complex):
a) ask the db admin to have - for each table you need to use - the corresponding schema name, then do "select * from lib1.tab1 join lib2.tab2 on [...]" ;-)
b) ask the db admin to create on schema "MyAlias" several alias (create alias) for each table you want to use. Then do "set current schema=MyAlias" followed by all the SQL statement you need e.g. "select * from tab1 join tab2". Since you’re querying myalias.tab1 which is an alias pointing to table lib1.tab1 it should work.
c) Complex: create your own SQL function that returns the corresponding schema_name for a table (e.g. myfunct('TAB1'). This could be done reading system view “qsys2.systables” where table_name=’TAB1’ and returning TABLE_SCHEMA column, which is a varchar(128). Once you got it, build up a dynamically prepared using the variable you just obtained. E.g.
"set mylib = myfunct('TAB1').
"set mystmt = 'select * from '||table_schema || ‘.tab1’ …”
Prepare mystmt and then execute mystmt.
I did something similar in VBA using ado ibmdrda and it worked.
hope this helps.
f.

Related

Spring Boot, R2DBC, Querydsl, query with parameter - MssqlBadGrammarException

When I run query with parameter Param<LocalDateTime>, using directly SQLServer2012Templates everything works fine.
[DEBUG] [||] com.querydsl.sql.AbstractSQLQuery, shows generated query with '?', but as I understand, it is not query sent to the SQL Server.
When the same query is run thru QuerydslR2dbcRepository I get exception:
o.r2dbc.mssql.ExceptionFactory$MssqlBadGrammarException: [102] [S0001] Incorrect syntax near '?'
dependencies:
implementation 'org.springframework.data:spring-data-r2dbc'
implementation 'io.r2dbc:r2dbc-mssql'
implementation 'com.infobip:infobip-spring-data-r2dbc-querydsl-boot-starter:7.0.0'
How to fix this?
The R2DBC spec team explicitly decided against following the JDBC syntax for bind parameter placeholders, see this discussion on the mailing list, which I've raised. This means that all JDBC based libraries either:
Have to support R2DBC explicitly, and implement the vendor specific per-driver syntax themselves
Won't support R2DBC bind variables (inline values are still possible, of course)
From what I discovered (and documented on said mailing list), the syntax is, at least:
-- Oracle and others
SELECT * FROM t WHERE id = :1
SELECT * FROM t WHERE id = :name
-- SQL Server
SELECT * FROM t WHERE id = #name
-- PostgreSQL
SELECT * FROM t WHERE id = $1
Your simplest options are thus:
Send a feature request to QueryDSL
Patch the generated SQL on the QueryDSL level or R2DBC level, or some other level, replacing all standalone ? markers by $n (this will be tricky with a regex, a simple parser that can recognise comments, string literals, etc. is probably required)
Work with R2DBC directly

Oracle create db link using a proxy schema

So I want to create a database link in oracle, my username is jefferson and I want to connect trough opms so I was told to do this.
create database link tmpp connect to jefferson[opms] identified by nothing using $something ;
For some reason when I try to use [] syntax it just tells me indentified is missing. Why is this not working, I was told to do it this way but I can't find any help in the official documentation for [] usage or the correct syntax.
You can create a fixed-user database link like this, but you need to enclose the entire proxy user identifier in double-quotes; and because it's now a quoted identifier the case has to match the DBA_USERS username, which is uppercase by default:
create database link tmpp connect to "JEFFERSON[OPMS]" identified by nothing using ... ;
As noted in MOS document 1477939.1 you can't create a connected-user database link (which you aren't trying to do); and the 30-character limit on identifiers applies, so the total length of both usernames plus the square brackets has to be 30 characters or less (which is also fine in your example).
However, as discussed in this related question, this functionality is currently broken in 11.2.0.4 and above because of bug 19191702.

How to get data from database according to string length without using any string function

I have to get the records from a table field where Length of record/data/string is greater then 8 characters. I cannot use any string function as the query has to be used on (MySQL, MSSQL, Oracle).
I don't want to do the below EXAMPLE:
List<String> names = new ArrayList<String>();
String st = select 'name' from table;
rs = executeSQL(st);
if ( rs != null )
{
rs.next();
names.add(rs.getString(1));
}
for(String name : names)
{
if(name.length() > 8)
result.add(name);
}
Any idea other then the one coded above? A query that can get the required result instead of processing on the retrieved data and then getting the required result.
Thank you for any help / clue.
JDBC Drivers may implement a JDBC escapes for the functions listed in appendix D (Scalar Functions) of the JDBC specification. A driver should convert the scalar functions it supports to the appropriate function on the database side. A list of the supported functions can be queried using 'DatabaseMetaData.getStringFunctions()'
To use this in a query you would then either use CHAR_LENGTH(string) or LENGTH(string) like :
SELECT * FROM table WHERE {fn CHAR_LENGTH(field)} > 8
You can replace CHAR_LENGTH with LENGTH. The driver (if it supports this function) will then convert it to the appropriate function in the underlying database.
From section 13.4.1 Scalar Functions of the JDBC 4.1 specification:
Appendix D “Scalar Functions" provides a list of the scalar functions
a driver is expected to support. A driver is required to implement
these functions only if the data source supports them, however.
The escape syntax for scalar functions must only be used to invoke the
scalar functions defined in Appendix D “Scalar Functions". The escape
syntax is not intended to be used to invoke user-defined or vendor
specific scalar functions.
I think you may be better off leveraging the power of the database and implementing a factory for your SQL statements (or perhaps for objects encapsulating your SQL functionality).
That way you can configure your factory with the name/type of the database, and it'll give you the appropriate SQL statements for that database. It gives you a clean means of parameterising this info, whilst allowing you to leverage the functionality of your databases and not having to replicate the database functionality in a suboptimal fashion in your code.
e.g.
DabaseStatementFactory fac = DatabaseStatementFactory.for(NAME_OF_DATABASE);
String statement = fac.getLongNames();
// then use this statement. It'll be configured for each db type
It's probably wise to encapsulate further and use something like:
DabaseStatementFactory fac = DatabaseStatementFactory.for(NAME_OF_DATABASE);
List<String> names = fac.getLongNames();
such that you're not making assumptions re. common schema and means of queries etc.
Another solution that I found is:
Select name from table where name like '________';
SQL counts the underscore (_) characters and return a name of length equal to number of underscore characters.

Programming function keys

Is there a way in Microsoft SQL Server Management Studio, to program a function key?
I'd like to map a function key to "SELECT * FROM dbo."
Yes, there is Tools-->Options-->Enviroment-->Keyboard
there are already a bunch there , you can type anything you want in the Stored Procedure column. However that will just execute, I guess you can do a PRINT 'SELECT * FROM fbo.' in your case
It's outside of the studio but I use AutoHotKey (google it). You can write little keyword macros. Even launch applications with a few keystrokes. All in an effort to reduce time on the mouse.
I would recommend that you use a free management studio tool called "SSMS Tools Pack" from Mladen Prajdic. It has a feature called SQL snippets where you can map snippets of SQL code to predefined keystrokes ("ssf" + ENTER" will do what you want using the tool).
I use it every day at different clients and its part of my SQL toolkit. Check it out here:
www.ssmstoolspack.com.
Eric
In SSMS:
Tools
Options
Keyboard
Select the desire shortcut (only 12 options, 3 of which are hard-coded and cannot be changed, which is better than none, but not by much)
Enter what you'd want run (for example, I have CTRL+0 set to "USE tempdb"
Save
These hotkeys will not be available to currently opened query windows, only windows opened after you've created them.
Note that if you make it a procedure call, such as as CTRL+1's "sp_who", hilight a block of text, and hit the hot key, the highlit text is passed in as a parameter to the procedure. Try it with CTRL+1 and see. (...and you get lots of fun and games with embedded periods which can be overridden by [bracketing it], but you'll find out about that as you go along.)
SSMSBoost add-in has this feaure:
you can define tokens and replacements for them. Example:
sel -> select * from
upd -> update # set where
symbol "#" defines, where cursor will be placed after replacement is done. You can define your own replacements.
There are certainlny much more features, for example Hitting F2 in SQL Editor will immediately script object, located at cursor. It is something like "go to definition" function in Visual Studio.

Is there any C SQLite API for quoting/escaping the name of a table?

It's impossible to sqlite3_bind_text a table name because sqlite3_prepare_v2 fails to prepare a statement such as:
SELECT * FROM ? ;
I presume the table name is needed to parse the statement, so the quoting needs to have happened before sqlite3_prepare_v2.
Is there something like a sqlite3_quote_tablename? Maybe it already exists under a name I can't recognize, but I can't find anything in the functions list.
SQLite will escape identifiers for you with the %w format in the https://www.sqlite.org/printf.html family of functions.
your proposed sqlite3_quote_tablename function could sanitize the input to prevent sql injection attacks. To do this it could parse the input to make sure it is a string literal. http://sqlite.org/lang_expr.html#litvalue
If a table name has invalid characters in it you can enclose the table name in double quotes, like this.
sqlite> create table "test table" (id);
sqlite> insert into "test table" values (1);
sqlite> select * from "test table";
id
----------
1
Of course you should avoid using invalid characters whenever possible. It complicates development and is almost always unnecessary (IMO the only time it is necessary is when you inherit a project that is already done this way and it's too big to change).
When using SQLite prepared statements with parameters the parameter: "specifies a placeholder in the expression for a literal value that is filled in at runtime"
Before executing any SQL statement, SQLite "compiles" the SQL string into a series of opcodes that are executed by an internal Virtual Machine. The table names and column names upon which the SQL statement operates are a necessary part of the compilation process.
You can use parameters to bind "values" to prepared statements like this:
SELECT * FROM FOO WHERE name=?;
And then call sqlite3_bind_text() to bind the string gavinbeatty to the already compiled statement. However, this architecture means that you cannot use parameters like this:
SELECT * FROM ? WHERE name=?; // Can't bind table name as a parameter
SELECT * FROM FOO WHERE ?=10; // Can't bind column name as a parameter
If SQLite doesn't accept table names as parameters, I don't think there is a solution for your problem...
Take into account that:
Parameters that are not assigned values using sqlite3_bind() are treated as NULL.
so in the case of your query, the table name would be NULL which of course is invalid.
I was looking for something like this too and couldn't find it either. In my case, the expected table names were always among a fixed set of tables (so those were easy to validate). The field names on the other hand weren't so I ended up filtering the string, pretty much removing everything that was not a letter, number, or underscore (I knew my fields would fit this parameters). That did the trick.

Resources