diff --git a/project.clj b/project.clj index 211823d7540efbf1e3cf48c981f5ed093e19f629..381d1691d1472935787fd47500ad879acdfdee96 100644 --- a/project.clj +++ b/project.clj @@ -41,6 +41,7 @@ com.sun.jmx/jmxri]] [medley "0.7.0"] ; lightweight lib of useful functions [mysql/mysql-connector-java "5.1.37"] ; MySQL JDBC driver + [net.sourceforge.jtds/jtds "1.3.1"] ; SQL Server driver [org.liquibase/liquibase-core "3.4.1"] ; migration management (Java lib) [org.slf4j/slf4j-log4j12 "1.7.12"] [org.yaml/snakeyaml "1.16"] ; YAML parser (required by liquibase) diff --git a/src/metabase/driver/generic_sql/query_processor.clj b/src/metabase/driver/generic_sql/query_processor.clj index f2238d9ebf006ff4179191fcff46035d5c5ea9a0..a1ddee52dada28738633ac4e557c923a78a3a883 100644 --- a/src/metabase/driver/generic_sql/query_processor.clj +++ b/src/metabase/driver/generic_sql/query_processor.clj @@ -5,7 +5,6 @@ [clojure.string :as s] [clojure.walk :as walk] [korma.core :refer :all, :exclude [update]] - [korma.sql.utils :as utils] [metabase.config :as config] [metabase.driver :as driver] [metabase.driver.query-processor :as qp] diff --git a/src/metabase/driver/mysql.clj b/src/metabase/driver/mysql.clj index fadc19bc5fd837b4eb5cfc97990eec7e4a99b1e5..e776196443e38e8f3c0ddb02b6f611ce07bed0f8 100644 --- a/src/metabase/driver/mysql.clj +++ b/src/metabase/driver/mysql.clj @@ -58,10 +58,8 @@ :VARCHAR :TextField :YEAR :IntegerField}) -(defn- connection-details->spec [details] - (-> details - (set/rename-keys {:dbname :db}) - kdb/mysql)) +(defn- connection-details->spec [details-map] + (kdb/mysql (set/rename-keys details-map {:dbname :db}))) (defn- unix-timestamp->timestamp [field-or-value seconds-or-milliseconds] (utils/func (case seconds-or-milliseconds diff --git a/src/metabase/driver/sqlserver.clj b/src/metabase/driver/sqlserver.clj new file mode 100644 index 0000000000000000000000000000000000000000..c0f3a1679fb7d64aa7fc4b88f787a197582c1753 --- /dev/null +++ b/src/metabase/driver/sqlserver.clj @@ -0,0 +1,114 @@ +(ns metabase.driver.sqlserver + (:require (korma [core :as k] + [db :as kdb]) + [korma.sql.utils :as utils] + (metabase.driver [generic-sql :refer [sql-driver]] + [interface :refer [defdriver]])) + (:import net.sourceforge.jtds.jdbc.Driver)) ; need to import this in order to load JDBC driver + +(defn- connection-details->spec [details-map] + (assoc (kdb/mssql details-map) + :classname "net.sourceforge.jtds.jdbc.Driver" + :subprotocol "jtds:sqlserver")) + +(def ^:private ^:const column->base-type + "See [this page](https://msdn.microsoft.com/en-us/library/ms187752.aspx) for details." + {:bigint :BigIntegerField + :binary :UnknownField + :bit :UnknownField + :char :CharField + :cursor :UnknownField + :date :DateField + :datetime :DateTimeField + :datetime2 :DateTimeField + :datetimeoffset :TimeField + :decimal :DecimalField + :float :FloatField + :geography :UnknownField + :geometry :UnknownField + :hierarchyid :UnknownField + :image :UnknownField + :int :IntegerField + :money :DecimalField + :nchar :CharField + :ntext :TextField + :numeric :DecimalField + :nvarchar :TextField + :real :FloatField + :smalldatetime :DateTimeField + :smallint :IntegerField + :smallmoney :DecimalField + :sql_variant :UnknownField + :table :UnknownField + :text :TextField + :time :TimeField + :timestamp :UnknownField ; not a standard SQL timestamp, see https://msdn.microsoft.com/en-us/library/ms182776.aspx + :tinyint :IntegerField + :uniqueidentifier :UUIDField + :varbinary :UnknownField + :varchar :TextField + :xml :UnknownField}) + +(defn- date [unit field-or-value]) + +(defn- date-interval [unit amount]) + +(defn- unix-timestamp->timestamp [field-or-value seconds-or-milliseconds]) + +(defdriver sqlserver + (sql-driver {:driver-name "SQL Server" + :details-fields [{:name "host" + :display-name "Host" + :default "localhost"} + {:name "port" + :display-name "Port" + :type :integer + :default 1433} + {:name "dbname" + :display-name "Database name" + :placeholder "birds_of_the_word"} + {:name "user" + :display-name "Database username" + :placeholder "What username do you use to login to the database?" + :required true} + {:name "password" + :display-name "Database password" + :type :password + :placeholder "*******"}] + :sql-string-length-fn :LEN + :column->base-type column->base-type + :connection-details->spec connection-details->spec + :date date + :date-interval date-interval + :unix-timestamp->timestamp unix-timestamp->timestamp})) + +(defn x [] + (metabase.driver/process-query {:database 85 + :type :native + :native {:query "SELECT COUNT(*) AS \"count\" FROM TABLES; GO"}})) + +(defn y [] + (let [entity (metabase.driver.generic-sql.util/korma-entity (Database 85) {:name "sys.tables"})] + (k/sql-only + (k/select entity (k/limit 1))))) + +(defn a [] + (let [entity (metabase.driver.generic-sql.util/korma-entity (Database 85) {:name "sys.tables"})] + (k/sql-only + (k/select entity + (k/modifier "TOP 1"))))) + +(defn b [] + (let [entity (metabase.driver.generic-sql.util/korma-entity (Database 85) {:name "sys.tables"})] + (k/select entity + (k/modifier (utils/func :TOP 1))))) + +(defn c [] + (-> (k/select* (metabase.driver.generic-sql.util/korma-entity (Database 85) {:name "sys.tables"})) + (k/modifier (utils/func "TOP %s" [1])))) + +(defn d [] + (k/exec (c))) + +(defn e [] + (k/as-sql (c)))