branch: elpa/emacsql commit bd6e02db55a9b2ca8c4065437df137964ebdd5df Author: Christopher Wellons <well...@nullprogram.com> Commit: Christopher Wellons <well...@nullprogram.com>
Be much more strict with identifiers. The form table:column now convers to table.column. --- emacsql-tests.el | 11 ++++++----- emacsql.el | 28 ++++++++++++++++------------ 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/emacsql-tests.el b/emacsql-tests.el index cec191f6a9..19299426a7 100644 --- a/emacsql-tests.el +++ b/emacsql-tests.el @@ -8,11 +8,12 @@ (ert-deftest emacsql-escape-identifier () (should (string= (emacsql-escape-identifier "foo") "foo")) (should (string= (emacsql-escape-identifier 'foo) "foo")) - (should (string= (emacsql-escape-identifier :foo) "':foo'")) - (should (string= (emacsql-escape-identifier "a b") "'a b'")) - (should (string= (emacsql-escape-identifier '$foo) "'$foo'")) - (should (string= (emacsql-escape-identifier "foo$") "foo$")) - (should (string= (emacsql-escape-identifier "they're") "'they''re'"))) + (should (string= (emacsql-escape-identifier :foo) "foo")) + (should-error (emacsql-escape-identifier "a b")) + (should-error (emacsql-escape-identifier '$foo)) + (should-error (emacsql-escape-identifier 10)) + (should (string= (emacsql-escape-identifier 'foo$) "foo$")) + (should (string= (emacsql-escape-identifier "foo:bar") "foo.bar"))) (ert-deftest emacsql-escape-value () (should (string= (emacsql-escape-value 'foo) "'foo'")) diff --git a/emacsql.el b/emacsql.el index 6f7596648b..43fb473aba 100644 --- a/emacsql.el +++ b/emacsql.el @@ -211,18 +211,22 @@ CONN-SPEC is a connection specification like the call to collect row into rows and do (setf row ()) finally (cl-return rows))))) -(defun emacsql-escape-identifier (identifier &optional force) +(defun emacsql-quote (string) + "Quote STRING for use in a SQL expression." + (format "'%s'" (replace-regexp-in-string "'" "''" string))) + +(defun emacsql-escape-identifier (identifier) "Escape an identifier, always with quotes when FORCE is non-nil." - (let ((string (if (stringp identifier) - identifier - (format "%S" identifier))) - (forbidden "[]-\000-\040!\"#%&'()*+,./:;<=>?@[\\^`{|}~\177]")) - (when (string-match-p "\n" string) - (error "Newlines not permitted in identifiers by emacsql.")) - (if (or force - (string-match-p forbidden string) - (string-match-p "^[0-9$]" string)) - (format "'%s'" (replace-regexp-in-string "'" "''" string)) + (let ((string (cl-typecase identifier + (string identifier) + (keyword (substring (symbol-name identifier) 1)) + (otherwise (format "%S" identifier)))) + (forbidden "[]-\000-\040!\"#%&'()*+,./;<=>?@[\\^`{|}~\177]")) + (when (or (string-match-p forbidden string) + (string-match-p "^[0-9$]" string)) + (error "Invalid Emacsql identifier.")) + (if (string-match-p ":" string) + (replace-regexp-in-string ":" "." string) string))) (defun emacsql--check-error (conn) @@ -278,7 +282,7 @@ CONN-SPEC is a connection specification like the call to (let ((print-escape-newlines t)) (cond ((null value) "NULL") ((numberp value) (prin1-to-string value)) - ((emacsql-escape-identifier (prin1-to-string value) t))))) + ((emacsql-quote (prin1-to-string value)))))) (defun emacsql-escape-vector (vector) "Encode VECTOR into a SQL vector scalar."