0

Switching my project from MySQL to MS SQL Server and have been having problems...

I'm using Slick and when I try to execute a query I'm getting the error

[SQLServerException: Incorrect syntax near '='.]

This is super descriptive except I'm not seeing what slick is trying to execute. So after some debugging I've narrowed it down to the filters that cause this exception.

//my join
var q = for {
  license <- License
  category <- Category if license.category === category.id
  keyContact <- Contact if license.keyContact === keyContact.id
  supplierContact <- Contact if license.supplierContact === supplierContact.id
  pricing <- Pricing if license.pricing === pricing.id
  location <- Location if license.location === location.id
  } yield (license,category,keyContact,supplierContact,pricing,location)
}

//THESE are the lines that don't work!
if(!approved.isDefined)           q=q.filter(!_._1.approved)
if(!pendings.isDefined)           q=q.filter(_._1.approved)
if(!completes.isDefined)          q=q.filter(x => (
    x._5.price === -1        ||
    x._5.serverCost === -1   ||
    x._5.depreciation === -1 ||
    ((x._5.maintCost === -1  || x._5.maintCost.isNull) &&
     x._1.maintAgreement === true)
    ))
if(!incompletes.isDefined)  q=q.filter(x => (
    x._5.price =!= -1 &&
    x._5.serverCost =!= -1 &&
    x._5.depreciation =!= -1 &&
    (x._1.maintAgreement === false || x._5.maintCost =!= -1)
    ))
//The join works if I don't have these filters. I have other filters I left out that do work for simplicity and readability 

The values that have isDefined called on them are just Options I pass into the function as filters. This code above works fine with MySQL but MSSQL doesn't seem to like it. Any thoughts?

What does it take for q=q.filter(!_._1.approved) to work at least? I've tried _._1 === false as well.

EDIT The debug info for the Query...

[debug] s.s.s.BaseSession - Preparing statement: select top 100 percent s25."id", s25."category", s25."tool", s25."supplier", s25."manufacturer", s25."licenseType", s25."version_edition", s25."location", s25."keyContact", s25."supplierContact", s25."supportedBy", s25."licenseEnd", s25."maintAgreement", s25."maintEnd",s25."count", s25."pricing", s25."compatibility_notes", s25."other_notes", s25."approved", s26."id", s26."name", s27."id", s27."nameFirst", s27."nameLast", s27."email", s27."phone", s28."id", s28."nameFirst", s28."nameLast", s28."email", s28."phone", s29."id", s29."price", s29."licenseOneTime", s29."depreciation", s29."maintCost", s29."serverCost", s29."purchCostSaved", s29."maintCostSaved", s30."id", s30."name", s30."city", s30."state", s30."country", s30."contact" from "licenses" s25, "categories" s26, "contacts" s27, "contacts" s28, "pricing" s29, "locations" s30 where (((((s25."category" = s26."id") and (s25."keyContact" = s27."id")) and (s25."supplierContact" = s28."id")) and (s25."pricing" = s29."id")) and (s25."location" = s30."id")) and (not s25."approved") order by s26."name", s25."tool", s25."manufacturer", s30."name", s25."supplier"

The useful part is the very end. Note that this is only querying when approved is not defined.

Solution What I did was change my projections to do a type conversion during the apply methods.

def * = id ~ category ~ tool ~ supplier ~ manufacturer ~ licenseType ~ version_edition ~
location ~ keyContact ~ supplierContact ~ supportedBy.? ~ licenseEnd.? ~ maintAgreement ~
maintEnd.? ~ count ~ pricing ~ compatibility_notes.? ~ other_notes.? ~ approved <> (
{l => License(l._1,l._2,l._3,l._4,l._5,l._6,l._7,l._8,l._9,l._10,l._11,l._12,
  (if(l._13 == 1)  true else false),l._14,l._15,l._16,l._17,l._18,(if(l._19 == 1)  true else false))},
{(l:License) => Some(l.id,l.category,l.tool,l.supplier,l.manufacturer,l.licenseType,l.version_edition,
  l.location,l.keyContact,l.supplierContact,l.supportedBy,l.licenseEnd,(if(l.maintAgreement) 1 else 0),
  l.maintEnd,l.count,l.pricing,l.compatibility_notes,l.other_notes,(if(l.approved) 1 else 0))})

It's not the ideal solution, but it works and is better than changing my case class to Int =].

damian
  • 1,419
  • 1
  • 22
  • 41
  • Is there any way you can get Slick to output the actual command it's trying to send to the database? Most SQL Server folks aren't going to be able reverse engineer the above code and somehow know what Slick is trying to do for you. – Aaron Bertrand Aug 06 '13 at 12:34
  • @AaronBertrand I don't know if there is a way or not for Slick to output the actual command. I don't think there is. – damian Aug 06 '13 at 12:39
  • Note that there are insane licensing fees for using slick-extensions with mssql. I'm starting to think type safe are evil. – JasonG Aug 06 '13 at 13:33
  • @JasonG What are you talking about? It's open source BSD license. EDIT: Nevermind you're talking about version 2.0.0. – damian Aug 06 '13 at 13:59
  • Yep. Slick support for DB2, Oracle, and now MS SQL will be under the typesafe subscription agreement via Slick Extensions. Slick itself is not however. http://slick.typesafe.com/doc/1.0.0/extensions.html – JasonG Aug 06 '13 at 17:23
  • @JasonG I'm still on 1.0.1 though. =] – damian Aug 06 '13 at 17:37
  • It's called scala-query then, correct? Edit - 1.0.0 introduced this evil licensing - sorry dawg. See here - bottom of the page. http://slick.typesafe.com/news/2013/02/07/slick-1.0.0-released.html BRUTALLLLL – JasonG Aug 06 '13 at 17:40
  • @JasonG These are only for Oracle and DB2. MSSQL is going to be added in 2.0. If it was part of extensions, I wouldn't even have access to it. – damian Aug 06 '13 at 17:43
  • AHHH right! Sorry I forgot it's specifically mssql that's in 2.0. Gotcha. Still a consideration if you're ever going to upgrade! – JasonG Aug 06 '13 at 17:51

1 Answers1

2

SQLServer doesn't support the ANSI Boolean Data Type. Instead it provides a BIT type which is, indeed, a numeric data type that lacks of the Boolean semantics (ANSI states that boolean supports three values true, false, unknown and of course the null).

Provided the previous considerations this couldn't be ascribed as a limit of Slick.

A simple workaround would consist to remap the Boolean data type to a numeric one and you should provide a «factory» layer if your goal is to develop a multi DBMS application.

EDIT (SQL GENERATED)

As you can see from the SQL generated you have

....
(not s25."approved")
....

which should be

....
(s25."approved" = 0)
....

Try manually the query: it should work now.

Lord of the Goo
  • 1,214
  • 15
  • 31
  • I'm using BIT, but I'm pretty sure Slick converts it to Boolean in Scala. I use it elsewhere in the application and it behaves correctly. Just not in the filter. – damian Aug 06 '13 at 12:38
  • Did you enable debug tracing in order to catch the SQL statement Slick built? – Lord of the Goo Aug 06 '13 at 12:41
  • If you mean on the server, I'm not sure if I can. I don't have full access to the server. I only have what I needed to write the application. I don't know much about databases other than basic use in applications. – damian Aug 06 '13 at 12:48
  • I mean client-side: enabling Slick logging would emit the SQL generated – Lord of the Goo Aug 06 '13 at 13:02
  • I'm having some trouble enabling logging for Slick. There's really no documentation for it. – damian Aug 06 '13 at 15:41
  • You're right… look at this thread on StackOverflow where I've just added a C&P solution (supposing you're playing with Play!) http://stackoverflow.com/questions/14453447/logging-options-for-slick – Lord of the Goo Aug 06 '13 at 15:55
  • You are saying manually do the query, I really can't do that. Did you see how long it was? And with all the options? There has to be a way for Slick to do it, or Slick needs to fix it. – damian Aug 06 '13 at 19:48
  • Hey man :) cut&paste the query and run it on SqlQuery Anlyzer or using Slick http://slick.typesafe.com/doc/1.0.1/sql.html… – Lord of the Goo Aug 06 '13 at 21:24
  • In any case if you seriously plan to benefit from slick orm (that is still under development don't forget that) I'll suggest you to try to change the mapped type and avoid direct SQL if you don't feel comfortable – Lord of the Goo Aug 06 '13 at 21:29
  • Well everything is still under development if you think that way... Slick(which isn't an ORM btw) is considered stable, but MS SQL is no longer going to be supported with the open source implemenatation(see comments on first answer). The reason I can't do direct SQL is because it has to be super dynamic. So I'm going to try my best at doing some hacky projection manipulations. And if that doesn't work, then just suck it up and use 0 and 1 in my scala code. I do appreciate your help though. – damian Aug 06 '13 at 23:52
  • Yeees, Slick is FRM… :) – Lord of the Goo Aug 07 '13 at 08:45