[Dbix-class] any Sybase users around?
Rafael Kitover
rkitover at io.com
Sun May 24 00:24:21 GMT 2009
Hello, I've done some hacking last night on getting various Sybase
stuffs to work.
I have a branch you can play with, though things are a bit rough around
the edges and need to be made more configurable, it should generally
work:
svn co \
http://dev.catalyst.perl.org/repos/bast/DBIx-Class/dbic/0.08/branches/sybase \
dbic-sybase
What's new:
* auto-pk for identity columns (this went into trunk too)
* placeholder support on Sybase versions that have it, which means you
get query caching but no last_insert_id (emulated with select max(col),
which should be good enough.)
* InflateColumn::DateTime support
What's old:
* limits/offset still don't work (more on that below)
* quoting stuffs is still not fixed (don't know much about that, only been
using Sybase for a day!)
Please try it out and let me know what you think.
THINGS THAT NEED MORE DISCUSSION FROM REAL SYBASE USERS:
-- PLACEHOLDERS
The branch code checks $dbh->{syb_dynamic_supported} to decide whether
or not to enable placeholder support.
There are advantages and disadvantages to having vs. not having it, so
it should really be configurable, through storage_type or a connect_info
option, WILL FIX.
On older versions of Sybase, using placeholders can actually be slower,
however on new versions it is significantly faster.
This is discussed in detail here:
http://search.cpan.org/~mewp/DBD-Sybase-1.09/Sybase.pm#Using_?_Placeholders_&_bind_parameters_to_$sth->execute
When not using placeholders (NoBindVars), it is possible to get the
last_insert_id using 'select @@identity', when using placeholders it
isn't possible and is emulated using 'select max(col)'.
This is slower of course, but since PKs are indexed it shouldn't be too
big of a deal.
Multiple autoinc columns are not an issue because Sybase can only have
one identity column per table.
-- NoBindVars and select @@identity
Can I do $dbh->prepare_cached('select @@identity') (for when not using
placeholders) or is that completely pointless?
-- DATES
The code is in DBIx::Class::Storage::DBI::Sybase::DateTime currently,
but needs to be factored out into a DateTime::Format::Sybase module,
which I'll try to do soon.
For output format, the most precise available in DBD::Sybase is ISO or
ISO_strict, I used ISO_strict:
2004-08-21T14:36:48.080Z
pattern => '%Y-%m-%dT%H:%M:%S.%3NZ'
Using $dbh->syb_date_fmt('ISO_strict') on connection.
More on this in the DBD::Sybase perldoc:
http://search.cpan.org/~mewp/DBD-Sybase-1.09/Sybase.pm#Controlling_DATETIME_output_formats
For input format I used $dbh->do('set dateformat mdy') and
pattern => '%m/%d/%Y %H:%M:%S.%3N'
There's no way (that I saw) to have the same format for both inflation
and deflation.
Since it really shouldn't be executing things by default (or without a
way to turn it off) this will be made configurable.
On input date formats:
http://manuals.sybase.com/onlinebooks/group-as/asg1250e/sqlug/@Generic__BookTextView/25357;pt=25420
On input time formats:
http://manuals.sybase.com/onlinebooks/group-as/asg1250e/sqlug/@ebt-link;pt=25357?target=%25N_25420_START_RESTART_N%25
Full input datetime format is "$date $time"
I didn't add support for SMALLDATETIME, this would either require IC::DT
changes, or making DATETIME map to a "timestamp" format and
SMALLDATETIME to a "date" format, which makes more sense, as
SMALLDATETIME has up to minute precision, while DATETIME has millisecond
precision.
Which would be the best solution?
SQL::Translator maps "timestamp" to DATETIME, but doesn't have a
mapping for SMALLDATETIME apparently in the Sybase producer.
Types:
http://www.colostate.edu/Services/ACNS/swmanuals/sasdoc/sashtml/accdb/z0439559.htm
-- LIMITS
There doesn't seem to be a good way to get a slice of a resultset with
offset in Sybase.
There's a discussion here:
http://www.dbforums.com/sybase/1616373-sybases-rownum-function.html
Some versions are supposed to have a ROWID function, but the version I
used: http://www.sybase.com/linuxpromo (page does not always load) does
not have it.
E.g.:
select rowid(table), table.* from table
Some versions of Sybase have TOP support, however, Sybase does not
support ORDER BY in a subquery (which breaks SQL::Abstract::Limit's TOP
support with order_by.)
E.g.:
select top 25 * from table
Another way is to set the session variable rowcount, this doesn't
support offsets however.
E.g.:
set rowcount 5
select * from table
The most promising method seemed to be a temp table with an IDENTITY
column, however, this breaks if you already have an IDENTITY column in
your table.
E.g:
select rownum=identity(10), * into #tempbar from bar
select * from #tempbar where rownum between 2 and 5
drop table #tempbar
Perhaps we can deploy some sort of iterator function and use an int
rownum column for the temp table. That seems to be the only way.
-- QUOTING
If I understand the issue correctly, this fails:
create table bar (baz int, quux int)
insert into bar (baz) values ('1')
Msg 257, Level 16, State 1:
Server 'HLAGH', Line 1:
Implicit conversion from datatype 'VARCHAR' to 'INT' is not allowed. Use the
CONVERT function to run this query.
There's a sybase_noquote branch, haven't looked at it yet.
I'm Caelum on irc.perl.org #dbix-class by the way.
More information about the DBIx-Class
mailing list