From e689bb17dc7f644f71e884d0b06013359d2f7a70 Mon Sep 17 00:00:00 2001
From: Xi Shen <davidshen84@gmail.com>
Date: Wed, 8 Jun 2016 13:49:54 +0800
Subject: [PATCH] ob-sql.el: Support sqlcmd in Cygwin environment

* etc/ORG-NEWS: Add "Improved support to Microsoft SQL Server via
  ~sqlcmd~" section to addresss this change.

* lisp/ob-sql.el (org-babel-sql-dbstring-mssql): Format Microsoft
  `sqlcmd' command line args.
(org-babel-sql-convert-standard-filename): Convert a Posix path to
Windows long path in Cygwin environment, or do nothing.
(org-babel-execute:sql): Add `mssql' engine support and remove support
for `msosql' engine.

The `osql' command line tool was last updated in 2004,
https://technet.microsoft.com/en-us/library/aa214012(v=sql.80).aspx, and
could not output the query result in a way that morden `org-table.el'
expects.  The `sqlcmd' is the preferred command line tool to connect the
Microsoft SQL Server and it also has a Linux version,
https://msdn.microsoft.com/en-us/library/hh568447(v=sql.110).aspx.

TINYCHANGE
---
 etc/ORG-NEWS   | 20 ++++++++++++++++++++
 lisp/ob-sql.el | 36 +++++++++++++++++++++++++++++++++---
 2 files changed, 53 insertions(+), 3 deletions(-)

diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS
index ed44a21..8af7423 100644
--- a/etc/ORG-NEWS
+++ b/etc/ORG-NEWS
@@ -210,6 +210,26 @@ mandatory):
  :database <database>
  :dbpassword <secret>
 #+END_EXAMPLE
+**** Improved support to Microsoft SQL Server via ~sqlcmd~
+=ob-sql= library removes support to the ~msosql~ engine which uses the
+deprecated ~osql~ command line tool, and replaces it with ~mssql~
+engine which uses the ~sqlcmd~ command line tool.  Use with properties
+like this:
+
+#+BEGIN_EXAMPLE
+  :engine mssql
+  :dbhost <host.com>
+  :dbuser <username>
+  :dbpassword <secret>
+  :database <database>
+#+END_EXAMPLE
+
+If you want to use the *trusted connection* feature, omit *both* the
+=dbuser= and =dbpassword= properties and add =cmdline -E= to the
+properties.
+
+If your Emacs is running in a Cygwin environment, the =ob-sql= library
+can pass the converted path to the =sqlcmd= tool.
 **** Support for additional plantuml output formats
 The support for output formats of [[http://plantuml.com/][plantuml]] has been extended to now
 include:
diff --git a/lisp/ob-sql.el b/lisp/ob-sql.el
index 6488afe..fdf73a0 100644
--- a/lisp/ob-sql.el
+++ b/lisp/ob-sql.el
@@ -62,6 +62,7 @@
 (declare-function org-table-import "org-table" (file arg))
 (declare-function orgtbl-to-csv "org-table" (table params))
 (declare-function org-table-to-lisp "org-table" (&optional txt))
+(declare-function cygwin-convert-file-name-to-windows "cygw32.c" (file &optional absolute-p))
 
 (defvar org-babel-default-header-args:sql '())
 
@@ -103,6 +104,28 @@ Pass nil to omit that arg."
   "Make Oracle command line args for database connection."
   (format "%s/%s@%s:%s/%s" user password host port database))
 
+(defun org-babel-sql-dbstring-mssql (host user password database)
+  "Make sqlcmd commmand line args for database connection.
+`sqlcmd' is the preferred command line tool to access Microsoft
+SQL Server on Windows and Linux platform."
+  (mapconcat #'identity
+	     (delq nil
+		   (list (when host (format "-S \"%s\"" host))
+			 (when user (format "-U \"%s\"" user))
+			 (when password (format "-P \"%s\"" password))
+			 (when database (format "-d \"%s\"" database))))
+	     " "))
+
+(defun org-babel-sql-convert-standard-filename (file)
+  "Convert the file name to OS standard.
+If in Cygwin environment, uses Cygwin specific function to
+convert the file name. Otherwise, uses Emacs' standard conversion
+function."
+  (format "\"%s\""
+	  (if (fboundp 'cygwin-convert-file-name-to-windows)
+	      (cygwin-convert-file-name-to-windows file)
+	    (convert-standard-filename file))))
+
 (defun org-babel-execute:sql (body params)
   "Execute a block of Sql code with Babel.
 This function is called by `org-babel-execute-src-block'."
@@ -129,10 +152,14 @@ This function is called by `org-babel-execute-src-block'."
 				      (or cmdline "")
 				      (org-babel-process-file-name in-file)
 				      (org-babel-process-file-name out-file)))
-                    (`msosql (format "osql %s -s \"\t\" -i %s -o %s"
+		    (`mssql (format "sqlcmd %s -s \"\t\" %s -i %s -o %s"
 				     (or cmdline "")
-				     (org-babel-process-file-name in-file)
-				     (org-babel-process-file-name out-file)))
+				     (org-babel-sql-dbstring-mssql
+				      dbhost dbuser dbpassword database)
+				     (org-babel-sql-convert-standard-filename
+				      (org-babel-process-file-name in-file))
+				     (org-babel-sql-convert-standard-filename
+				      (org-babel-process-file-name out-file))))
                     (`mysql (format "mysql %s %s %s < %s > %s"
 				    (org-babel-sql-dbstring-mysql
 				     dbhost dbport dbuser dbpassword database)
@@ -173,6 +200,9 @@ SET MARKUP HTML OFF SPOOL OFF
 SET COLSEP '|'
 
 ")
+	 (`mssql "SET NOCOUNT ON
+
+")
 	 (_ ""))
        (org-babel-expand-body:sql body params)))
     (org-babel-eval command "")
-- 
2.8.3

