buffer-local values for SQL query parameters - sql

Using sql-send-buffer, I can send a SQL query from a file to an open SQL REPL. Many of my queries have parameter placeholders (in Postgres syntax, $1, $2 &c.) . Does anyone have code analogous to sql-send-buffer that will prompt for values to fill in for these parameters? Ideally, I'd like it to store the values I provide, and not prompt again unless I add parameters or close the file.
Currently I either:
replace the parameters in the file, try to remember not to commit or deploy these test values (error prone)
copy the query into the REPL, replace parameters there (tedious)

Something like this, perhaps:
(defvar my-sql-replacements nil)
(make-variable-buffer-local 'my-sql-replacements)
(defun my-sql-send-buffer-replace ()
(interactive)
(let ((string (buffer-substring-no-properties (point-min) (point-max))))
(while (string-match "[$][0-9]" string)
(let* ((placeholder (match-string 0 string))
(replacement (or (cdr (assoc placeholder my-sql-replacements))
(read-string (format "Replacement for %s: " placeholder)))))
(unless (assoc placeholder my-sql-replacements)
(push (cons placeholder replacement) my-sql-replacements))
(setq string (replace-regexp-in-string (regexp-quote placeholder) replacement string))))
(sql-send-string string)))
I haven't tested it with an actual SQL server, but from tracing sql-send-string it looks like it should work. It stores the replacements in a buffer-local variable.

Related

How to show an unknown list of variables and their values, if possible

As mentioned before in some questions with "Progress-4GL" and "OpenEdge" tags, I'm working with AppBuilder and Procedure editor. As a result, the debugging possibilities are extremely limited: for knowing the value of a variable, I need to do show them on screen, something like this:
MESSAGE "temp1=[" temp1 "], temp2=[" temp2 "]" VIEW-AS ALERT-BOX.
I can also put that information in a logfile, but that's not the main point here.
I would like to write a procedure, which can handle this, something like:
PROCEDURE SHOW_VARIABLES_AND_VALUES (INPUT I1, INPUT I2, ...):
1. <put parameter names and values together inside one string> => """I1="" I1"
2. <do this for all input parameters (the number is unknown)> => """I1="" I1, ""I2="" I2, ..."
3. <how to use this (MESSAGE VIEW-AS ALERT-BOX, LOG, ...) there I'll know what to do>
Does anybody know how to handle the fist two points (put variable name and value together and handle an unknown number of input parameters)?
Thanks in advance
You can use SUBSTITUTE function.
MESSAGE SUBSTITUTE ("temp1=&1 ~ntemp2=&2 ~n temp3=&3",
temp1,
temp2,
temp3) VIEW-AS ALERT-BOX.
Unfortunately there is no dynamic access to variables or parameters. So there's no way to automatically add all input parameters to a message string. Also there is no anytype parameter type in the ABL - for user defined functions or procedures. So you'd have to use the STRING() function a lot to convert your input parameters to string as the best fit parameter for everything.
The built in SUBSTITUTE function on the other hand can handle anytype of arguments. So temp1, temp2 and temp3 can actually be variables or parameters of any datatype.
As mentioned in one of my comments on one of your earlier questions: Give the OpenEdge debugger a chance. The debugger outside of Progress Developer studio looks historic. But it does it's job.
Meanwhile I've decided to use following system (as my request seems to be impossible):
MESSAGE "temp1=[" temp1 "]~n" ~
"temp2=[" temp2 "]~n" ~
"temp3=[" temp3 "]~n" ~
"temp4=[" temp4 "]" ~
VIEW-AS ALERT-BOX.
In order to make it easy to work with, I've found out the following keyboard "shortcut" for the tilde character: ALT+0126.
As indicated by Stefan, this is far better (no tilde and no shortcut needed):
MESSAGE "temp1=[" temp1 "]" SKIP
"temp2=[" temp2 "]" SKIP
"temp3=[" temp3 "]" SKIP
"temp4=[" temp4 "]" SKIP
VIEW-AS ALERT-BOX.

Delimiting output in Lisp

I'm sure this is a very basic question, but how to output delimited values?
(defun q (n)
(if (<= n 2)
1
(+
(q (- n (q (- n 1))))
(q (- n (q (- n 2)))))))
(loop for x from 1 to 25
do (
write (q x)))
The above outputs the first 25 terms of the Hofstadter Q-sequence, but concatenated:
11233455666888109101111121212121614
Can be comma-, space- or tab-delimited. I tried playing with the format function, but it's way over my head for a Lisp newbie like me.
You can write the delimiter yourself, e. g. (write ", "). You can also write the (platform dependent) line separator with (terpri).
As for format, you can get by with some basic usage at first:
(format <stream> <template> <args…>)
<stream> is where the output should go. For standard output, use t. In order to write to a file, you would use the stream created by with-open-file here.
<template> is a template string. That's just a string, but the ~ character is special. For starters, just use ~a wherever you want to insert an argument.
<args…> are exactly as many further arguments as you used ~a above.
Using this simple toolbox, you could do: (format t "~a, " (q x)) for each item.
Format has a lot of other possibilities, e. g. it can iterate a list by itself, do different output formats and escaping, or even be extended by user functions. Look that up in the hyperspec (e. g. at clhs.lisp.se).
use write-char or, indeed, format:
(format t "~D: ~:D~%" x (q x))

Is there a way to change delimiters of documentation string in Common Lisp?

I sometimes put examples of function calls and their output in the documentation string of a function definition.
(defun js-[] (&rest args)
"Javascript array literal statement.
(js-[] 1 2 3)
> \"[1, 2, 3]\"
"
(format nil "[~{~A~^, ~}]" (mapcar #'js-expr args)))
But sometimes the output of the function is a string. So I have to escape the double quotes in the example output. This becomes tedious very quickly.
Is there a way to change the docstring delimiter from double quotes to something else so I don't have to keep escaping them?
Please note that sometimes it's worse than just escaping once:
(defun js-~ (str)
"Javascript string statement. This is needed so that double quotes are inserted.
(js-~ \"string\")
> \"\\\"string\\\"\"
"
(format nil "\"~A\"" str))
Here there is an additional problem. Reading the docstring is difficult.
TL;DR
Yes, you can, no, you do not want to do it.
No, CL has just one syntax for strings
The only way to represent a string in Common Lisp is to use
Double-Quote ".
Yes, you can modify the reader so that something else denotes a string
E.g., suppose you want to a string to be started and stopped by, say, #.
(This is an ordinary character rarely used in symbol names,
in contrast to % and $ which are often used in implementation-internal symbols.)
Set the properties of # from ":
(multiple-value-bind (function non-terminating-p)
(get-macro-character #\")
(set-macro-character #\# function non-terminating-p))
Now:
(read-from-string "#123#")
==> "123" ; 5
(read-from-string #"123"#)
==> "123" ; 5
Do not forget to restore the input syntax to standard Common Lisp syntax:
(setq *readtable* (copy-readtable nil))
See Reader.
You might be able to modify the printer
The standard does not require that the printing of standard objects
(such as a string) to be
used-modifiable.
You can try defining a print-object method:
(defmethod print-object ((o string) (d stream))
...)
however,
implementing this correctly is not easy
this is non-conforming code (defining a method for a standardized generic function which is applicable when all of the arguments are direct instances of standardized classes)
thus many implementations will signal errors on this code,
even if you disable package locks &c, the implementation is free to ignore your method.
No, you do not want to do that
The code exists for people to read it.
Changing Lisp syntax will make it harder for others to read your code.
It will also confuse various tools you use (editor &c).
CL has many warts, but this is not one of them ;-)
PS. See also documentation and describe, as well as comment syntax Sharpsign Vertical-Bar and Semicolon.
You could make a reader macro that slurps in a multi line string like this:
(defun hash-slash-reader (stream slash arg)
(declare (ignore slash arg))
(loop :with s := (make-string-output-stream)
:for c := (read-char stream)
:if (and (eql #\/ c) (eql #\# (peek-char nil stream)))
:do (read-char stream) (return (get-output-stream-string s))
:if (eql #\Newline c)
:do (peek-char t stream)
:do (princ c s)))
(set-dispatch-macro-character #\# #\/ #'hash-slash-reader)
Now you can do:
(defun js-~ (str)
#/ --------------------------
Javascript string statement.
This is needed so that double quotes are inserted.
(js-~ "string")
> "\"string\""
-------------------------- /#
(format nil "\"~A\"" str))
The documentation string will be added just as if you'd written it with double quotes. This is effectively the same as changing the delimiter for strings!. In fact, it is an additional way to delimit strings.
Which is why you can use it (not recommended though) in regular lisp code, and not just for documentation purposes.
Using / as the sub-character of the dispatch macro, helps keep it conceptually close to the multiline comment, but avoids being ignored by the reader altogether.
Another idea. Write your docstrings as usual, without examples.
(defun js-~ (str)
"Javascript array literal statement."
...)
Define tests. That can be as simple as:
(defparameter *tests*
'(((js-~ "string") . "\"string\"")
...))
Use that list to perform tests:
(loop for (form . expected) in *tests*
for (fn . args) = form
for actual = (apply fn args)
do (assert (equalp actual expected)))
... and to update the documentation. Be careful, this appends to the existing documentation string, so don't run it twice.
(loop for (form . expected) in *tests*
for (fn . args) = form
do (setf (documentation fn 'function)
(format nil
"~a~%~% ~S~% => ~S"
(documentation fn 'function)
form
expected)))
You can (ab)use cl-interpol. Although the purpose of the library is to enable string interpolation it also allows custom string delimiters, if you don't mind preprending the string with #?. e.j.
CL-USER> (cl-interpol:enable-interpol-syntax)
; No values
CL-USER> #?'foo'
"foo"
CL-USER> #?/foo/
"foo"
CL-USER> #?{foo}
"foo"
CL-USER>
so after enabling the interpol reader macro you could write
(defun js-[] (&rest args)
#?'Javascript array literal statement.
(js-[] 1 2 3)
> "[1, 2, 3]"
'

Assign and print an input string to a variable. Lisp

I want my program to ask for an expression, assign an inputted string to a variable 'exp' and then print the expression.
However I am having some trouble. I first tried using (read)
(princ "Enter a expression to be evaluated.")
(setf exp (read))
(princ exp)
However when i use this code, this happens.
Hello this is an expression ;This is what I input
Enter a expression to be evaluated.HELLO
T
I then tried to use (read-line), but when I do this, I don't seem to be asked for an input at all.
(princ "Enter a expression to be evaluated.")
(setf exp (read-line))
(princ exp)
gets
Enter a expression to be evaluated.
T
The program just ends.
After some answers I have come up with this
(defun get-input (prompt)
(clear-input)
(write-string prompt)
(finish-output)
(setf exp (read-line)))
(get-input "Enter an expression: ")
(princ exp)
However when i run this the following happens
My first sentence ;My first input
Enter an expression: My second sentence ;it then asks for input, i do so
My second sentence ;my second input is printed back at me
T
This is kind of a FAQ.
Output can be buffered. Use FINISH-OUTPUT to make sure that the output has actually reached its destination.
READ reads Lisp s-expressions. It returns the corresponding data-structure. It's only useful when you enter a valid s-expression.
READ-LINE reads a line and returns a string.
Example:
*
(defun ask (&optional (message "Input: "))
(clear-input) ; get rid of pending input
(write-string message) ;
(finish-output) ; make sure output gets visible
(read-line)) ; read a line as a string
ASK
* (ask "Name: ")
Name: Rainer
"Rainer"
NIL
File p.lisp:
(defun get-input (prompt)
(clear-input)
(write-string prompt)
(finish-output)
(read-line))
(write-string (get-input "Enter a sentence: "))
(finish-output)
Output
* (load "/tmp/p.lisp")
Enter a sentence: foo is not a bar
foo is not a bar
T

List all Emacs variables containing regexp

How do I find all variables containing "directory" in their name in Emacs?
M-x apropos-variable RET directory
If you simply want to find all variables containing a string, check out the correct answer. Here i created the list of pairs in the form (<variable> . <value>).
Explanation of functions used
mapatoms is a map-style function to operate on obarray, variable that contains all symbols used by Emacs.
prin1-to-string returns a string with the printed representation of an object.
string-match finds a regexp in a string, returns index or nil if not found.
push inserts element into a head of a list in-place.
remove-if is equivalent to inverted filter
mapcar is an ordinary map function
boundp returns t if variable's value is not void.
symbol-value returns value of a variable.
Final code
(let ((matching-variables
(let ((result '()))
;; result will contain only variables containing "directory"
(mapatoms (lambda (variable)
(let* ((variable-string (prin1-to-string variable))
(match (string-match "directory" variable-string)))
(if match
(push variable result)))))
result)))
;; returns list of pairs (variable-name . variable-value)
(remove-if #'null
(mapcar (lambda (variable)
(if (boundp variable)
(cons variable (symbol-value variable))
nil))
matching-variables)))
References
https://stackoverflow.com/a/8031385/596361