I had a similar problem and decided to create my own backend. One of the existing backends (C++?) was used as a template and I modified it to create the new back end which behaves like a dictionary.
In my setup SQLi buffers are automatically named to match the database that is being connected to, eg. *DB:DBASE1DM*
. The backend contains an alist for each database with the schemas, tables, and columns. When I want to complete something the name of the buffer is used to get the correct list of candidates for that database.
(defun ry/company-sql-upper-lower (&rest lst)
(nconc (sort (mapcar 'upcase lst) 'string<) lst))
(defvar ry/company-sql-alist
`(("DBASE1" ;; Database name w/o environment suffix.
"DBASE1DM" "DBASE1UM" ;; Database name with environment suffix.
"SCHEMA1" "SCHEMA2"
"TABLE1" "TABLE2"
"COLUMN1" "COLUMN2")
("DBASE2"
"DBASE2DM" "DBASE2UM"
"SCHEMA1" "SCHEMA2"
"TABLE1" "TABLE2"
"COLUMN1" "COLUMN2"))
"Alist mapping sql-mode to candidates.")
(defun ry/company-sql (command &optional arg &rest ignored)
"`company-mode' back-end for SQL mode based on database name."
(interactive (list 'interactive))
(cl-case command
(interactive (company-begin-backend 'ry/company-sql))
(prefix (and (assoc (substring (buffer-name (current-buffer)) 4 -3) ry/company-sql-alist)
(not (company-in-string-or-comment))
(or (company-grab-symbol) 'stop)))
(candidates
(let ((completion-ignore-case t)
(symbols (cdr (assoc (substring (buffer-name (current-buffer)) 4 -3) ry/company-sql-alist))))
(all-completions arg (if (consp symbols)
symbols
(cdr (assoc symbols company-sql-alist))))))
(sorted t)))
This has the downside that it's not a smart completion and that including new databases or making modifications to existing databases is a manual process. A couple queries can be used to gather the data and then it isn't very hard to massage it into the format needed for the backend.
The function below handles connecting to a database and changing the names of the buffers to match the database that is connected to.
(defun ry/sql-open-database (database username password)
"Open a SQLI process and name the SQL statement window with the name provided."
(interactive (list
(read-string "Database: ")
(read-string "Username: ")
(read-passwd "Password: ")))
(let ((u-dbname (upcase database)))
(setq sql-set-product "db2")
(sql-db2 u-dbname)
(sql-rename-buffer u-dbname)
(setq sql-buffer (current-buffer))
(sql-send-string (concat "CONNECT TO " database " USER " username " USING " password ";"))
(other-window 1)
(switch-to-buffer (concat "*DB:" u-dbname "*"))
(sql-mode)
(sql-set-product "db2")
(setq sql-buffer (concat "*SQL: " u-dbname "*"))))