How to set transform_null_equals postgres parameter on a connection? - postgresql

First some context in case it helps with your understanding of the why piece and sometimes leads to other good answers. I love this settings transform_null_equals because instead of
sql column value=NULL where I am told null means unknown
sql WHERE clause value=null where null means null
The setting in the title basically changes postgres so that null in WHERE clause AND column value BOTH mean 'unknown'. I can then say WHERE c.col=null (which means find any columns WHERE c.col is unknown) and I can also do WHERE c.col="value"
In this way in null languages, I can then do c.col=variable and variable can be null for unknown and a value for something that is known. perfect!
I realize this is a violation of the spec but it makes our team super fast(which is way more important in our business)....we have had less bugs, and WAY WAY simpler queries....OMG, way simpler.
Now, we set this on the user, but I want to set this via the connection instead so when someone installs postgres, it just magically works without them having to remember to set the setting.
How to do in jdbc?
Even better, How to do in Hikari Pool

You may have less trouble writing your queries with transform_null_equals, but I doubt that they will perform better, since this will just replace = NULL with IS NULL before the query is optimized.
Anyway, you can use the options parameter in a JDBC connection string to supply the parameter to the server process:
jdbc:postgresql:dbname?user=myuser&password=mypwd&options=-ctransform_null_equals%3Don

Related

Is 'jdbcType' necessary in a MyBatis resultMap?

When we use Mybatis , in <select> ...</select> statment I know we need set jdbcType beacuse the IN variable maybe null, but when I see the document of Mybatis, I found jdbcType in <result>...</result> under ResultMap. the document of the
jdbcTpe in <result>...</result> was:
... The JDBC type is only required for nullable columns upon insert, update or delete. This is a JDBC requirement, not a MyBatis one. So even if you were coding JDBC directly, you'd need to specify this type – but only for nullable values.
the bold word say only required for nullable columns upon insert, update or delete.
BUT,the element of result is used in select neither insert, update or delete.
so ,is it necessary use jdbcType in <result>...</result> ?
Most of the time, no. Why? Read on.
If you want to use a null as a JDBC parameter value you need to specify the jdbcType. That's a restriction of the JDBC specification you can't avoid. Therefore, if there's even a remote possibility a JDBC parameter could have a null value, then yes, specify it.
This does not apply to parameters preprocessed by MyBatis inside MyBatis tags, like the ones you use in the "test" attribute of the < if > tag. Those ones are not JDBC parameters.
Now, for the columns you read. These are the ones you are interested on. The thing is most of the time you don't need them. MyBatis will pick the right JDBC type for you. Well... this has been the case for me 99.999% of the time.
What about the other 0.001%? For some exotic column types -- that you rarely use -- MyBatis may pick the wrong JDBC type for you. The designers of MyBatis thought about this case, and give you the chance of overriding it. I think I remember an XML type database column that MyBatis was unsuccessfully trying to read as a VARCHAR, but I don't remember which database.
Bottom line, don't use it when reading columns, unless MyBatis reads exotic data type columns (XML, UUID, POINT, etc.) the wrong way.

Oracle DB link - where clause evaluation

i have a DB2 data source and an Oracle 12c target.
The Oracle has a DB link to the DB2 defined which is working in general.
Now i have a huge table in the DB2 which has a timestamp column (lets call it ROW_CHANGED) for row changes. I want to retrieve rows which have changed after a particular time.
Running
SELECT * FROM lib.tbl WHERE ROW_CHANGED >'2016-08-01 10:00:00'
on the DB2 returns exactly 1 row after ca. 90 secs which is fine.
Now i try the same query from the Oracle via the db link:
SELECT * FROM lib.tbl#dblink_name WHERE ROW_CHANGED >TO_TIMESTAMP('2016-08-01 10:00:00')
This runs for hours and ends up in a timeout.
I read some Oracle docs and found distributed query optimization tips but most of them refer to joining a local to a remote table which is not my case.
In my desperation, i have tried the DRIVING_SITE hint, without effect.
Now i wonder when the WHERE part of the query will be evaluated. Since i have to use Oracle syntax and not DB2 syntax for the query, is it possible the Oracle will try to first copy the full table and apply the where clause afterwards? I did some research but did not find anything which would help me in this direction.
The ROW_CHANGED is a hidden column in the DB2, if that matters.
Thx for any hint in advance.
Update
Thanks#all for help. I'll share what did the trick for me.
First of all i have used TO_TIMESTAMP since the DB2 column is also Timestamp (not date) and i had expected to circumvent implicit conversions by this.
Without the explicit conversion i ran into ORA-28534: Heterogeneous Services preprocessing error and i have no hope of touching the DB config within reasonable time.
The explain plan btw did not bring much. It showed a FULL hint and no conversion on the predicates. Indeed it showed the ROW_CHANGED column as Date, i wonder why.
I have tried Justins suggestion to use a bind variable, however i got ORA-28534 again. Next thing i did was to wrap it into a pl/sql block (will run in a SP anyway later).
declare
v_tmstmp TIMESTAMP := 01.08.16 10:00:00;
begin
INSERT INTO ORAUSER.TMP_TBL (SRC_PK,ROW_CHANGED)
SELECT SRC_PK,ROW_CHANGED
FROM lib.tbl#dblink_name
WHERE ROW_CHANGED > v_tmstmp;
end;
This was executing in the same time as in DB2 itself. The date format is DD.MM.YY here since it is the default unfortunately.
When changing the variable assignment to
v_tmstmp TIMESTAMP := TO_TIMESTAMP('01.08.16 10:00:00','DD.MM.YY HH24:MI:SS');
I got the same problem as before.
Meanwhile the DB2 operators have created an index in the ROW_CHANGED column which i requested earlier that day. This has solved the problem in general it seems. Even my original query finishes in no time now.
If you are actually using an Oracle-specific conversion function like to_timestamp, that forces the predicate to be evaluated on the Oracle side. Oracle isn't going to know how to convert a built-in function like to_timestamp into an exactly equivalent function call in DB2.
If you used a bind variable, that would be more likely to get evaluated on the DB2 side. But that may be complicated by the data type mapping between different databases-- there may not be a perfect mapping between one engine's date and another engine's timestamp data type. If this was a numeric column, a bind variable would be almost certain to get pushed. In this case, it probably involves playing around a bit to figure out exactly what data type to use for your variable that works for your framework, Oracle, and DB2.
If using a bind variable doesn't work, you can force the predicate to be evaluated on the remote server using the dbms_hs_passthrough package. That lets you send a query verbatim to the remote server which allows you to do things like use functions defined in your DB2 database. That's a bit of overkill in this situation, hopefully, but it's nice to have the hammer as your backup if the simpler solution doesn't work quickly enough.

Is there any logical reason to use CFQUERYPARAM in Query of Queries?

I primarily use CFQUERYPARAM to prevent SQL injection. Since Query-of-Queries (QoQ) does not touch the database, is there any logical reason to use CFQUERYPARAM in them? I know that values that do not match the cfsqltype and maxlength will throw an exception, but, these values should already be validated before that and display friendly messages (from a UX viewpoint).
Since Query-of-Queries (QoQ) does not touch the database, is there any logical reason to use CFQUERYPARAM in them? Actually, it does touch the database, the database that you currently have stored in memory. The data in that database could still theoretically be tampered with via some sort of injection from the user. Does that affect your physical database - no. Does that affect the use of the data within your application - yes.
You did not give any specific details but I would err on the side of caution. If ANY of the data you are using to build your query comes from the client then use cfqueryparam in them. If you can guarantee that none of the elements in your query comes from the client then I think it would be okay to not use the cfqueryparam.
As an aside, using cfqueryparam also helps optimize the query for the database although I'm not sure if that is true for query of queries. It also escapes characters for you like apostrophes.
Here is a situation where it's simpler, in my opinion.
<cfquery name="NoVisit" dbtype="query">
select chart_no, patient_name, treatment_date, pr, BillingCompareField
from BillingData
where BillingCompareField not in
(<cfqueryparam cfsqltype="cf_sql_varchar"
value="#ValueList(FinalData.FinalCompareField)#" list="yes">)
</cfquery>
The alternative would be to use QuotedValueList. However, if anything in that value list contained an apostrophe, cfqueryparam will escape it. Otherwise I would have to.
Edit starts here
Here is another example where not using query parameters causes an error.
QueryAddRow(x,2);
QuerySetCell(x,"dt",CreateDate(2001,1,1),1);
QuerySetCell(x,"dt",CreateDate(2001,1,11),2);
</cfscript>
<cfquery name="y" dbtype="query">
select * from x
<!---
where dt in (<cfqueryparam cfsqltype="cf_sql_date" value="#ValueList(x.dt)#" list="yes">)
--->
where dt in (#ValueList(x.dt)#)
</cfquery>
The code as written throws this error:
Query Of Queries runtime error.
Comparison exception while executing IN.
Unsupported Type Comparison Exception:
The IN operator does not support comparison between the following types:
Left hand side expression type = "DATE".
Right hand side expression type = "LONG".
With the query parameter, commented out above, the code executes successfully.

Null db values and defaults

I have 2 fields that I'm adding to a current database table with data in it. One is a bit and one is an int. If I am setting defaults for both, should I just set them to not null since there is no case where they would be null?
If you will ever need to store data where you need the ability to indicate "we don't know" then you may consider allowing null values.
For example, I store data from remote sensors. When I am unable to retrieve the sensor data, like due to network problems, I use null.
If, however, you require that a value always be present, then you should use the NOT NULL constraint.
Yes, that would do the trick. If you set those columns as not null and you don't specify a default value, you'll definitely get an error from the DB.

Null value in Database

Null value means
No value
Inapplicable,unassigned, unknown, or unavailable
Which is true?
It's all about the context in which it's used. A null means there is no value but the reason for this will depend on the domain in which it is being used. In many cases the items you've listed are all valid uses of a null.
It can mean any of those things (and it is not always obvious which), which is one argument against using nulls at all.
See: http://en.wikipedia.org/wiki/Null_(SQL)#Controversy
From Wikipedia
Null is a special marker used in
Structured Query Language (SQL) to
indicate that a data value does not
exist in the database. Introduced by
the creator of the relational database
model, E. F. Codd, SQL Null serves to
fulfill the requirement that all true
relational database management systems
(RDBMS) support a representation of
"missing information and inapplicable
information". Codd also introduced the
use of the lowercase Greek omega (ω)
symbol to represent Null in database
theory. NULL is also an SQL reserved
keyword used to identify the Null
special marker.
Obviously you have the DB definition of what null means, however to an application it can mean anything. I once worked on a strange application (disclaimer- I didn't design it), that used null in a junction table to represent all of the options (allegedly it was designed this way to "save space"). This was a DB design for user and role management.
So null in this case meant the user was in all roles. That's one for daily WTF. :-)
Like many people I tend to avoid using nulls where realistically possible.
null indicates that a data value does not exist in the database, thus representing missing information.
Also allows for three-way truth value; true, false and unknown.
The only answer supported by SQL semantics is "unknown." If it meant "no value," then
'Hi there' = NULL
would return FALSE, but it returns NULL. This is because the NULL value in the expression means an unknown value, and the unknown value could very well be 'Hi there' as far as the system knows.
NULL is a representation that a field has not had a value set, or has been re-set to NULL.
It is not unknown or unavailable.
Note, that when looking for NULL values, do not use '=' in a where clause, use 'is', e.g.:
select * from User where username is NULL;
Not:
select * from User where username = NULL;
NULL, in the relational model, means Unknown. It's a mark that appears instead of a value wherever a value can appear in SQL.
Null means nothing, unknown and no value.
It does not mean unavailable or in applicable.
Null is a testable state of a column in a row, but it has no value itself.
By example:
An int can be only ...,0,1,2,3,... and also NULL.
An datetime can be only a valid date... and also NULL.
A bit can be only 0 or 1... and also NULL.
An varchar can be a string... and also NULL.
see the pattern?
You can make a column NOT NULL-able so that you can force a column to take a value.
The NULL SQL keyword is used to represent either a missing value or a value that is not applicable in a relational table
all :-)
if you want to add a semantic meaning to your field, add an ENUM
create TABLE myTable
(
myfield varchar(50)
myfieldType enum ('OK','NoValue','InApplicable','Unassigned','Unknown','Unavailable') NOT NULL
)