all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* Interacting with PostgreSQL
@ 2020-11-21 23:51 Tim Landscheidt
  2020-11-22  1:33 ` Jean Louis
  2020-11-22 21:33 ` Marcin Borkowski
  0 siblings, 2 replies; 13+ messages in thread
From: Tim Landscheidt @ 2020-11-21 23:51 UTC (permalink / raw)
  To: help-gnu-emacs

Hi,

I've been using Emacs with PostgreSQL for a bit more than
20 years now, and every now and then I look at Emacs's SQL
"stuff" and think that I'm doing something absurdly wrong,
but can never find a better solution.  So I'd like to pre-
sent you with three scenarios, my tried and tested workflow
for each of them and ask for your input on solving them more
Emacsily.

1. Mass data and structure changes: These are changes where
   I'd like to see the result or test triggers & Co. before
   committing them.  For that, I have a function to create a
   scratch buffer for SQL commands in a transaction:

   | (defun tl-sql-scratch nil
   |   "Create a scratch buffer for PostgreSQL."
   |   (interactive)
   |   (switch-to-buffer (generate-new-buffer "scratch.sql"))
   |   (sql-mode)
   |   (sql-highlight-postgres-keywords)
   |   (insert "BEGIN WORK;\n-- COMMIT WORK;\n")
   |   (forward-line -1))

   and set [f12] to pipe the buffer's contents to psql:

   | (define-key sql-mode-map
   |   [f12]
   |   (lambda nil
   |     (interactive)
   |     (shell-command-on-region
   |      (point-min)
   |      (point-max)
   |      "/usr/bin/psql")))

   I then add UPDATEs, CREATE FUNCTIONs, test cases, etc.,
   press [f12] until I am satisfied with the results, remove
   the test cases, uncomment the COMMIT and then press [f12]
   for the last time before killing the buffer.

   The closest replacement for that that I have come across
   is sql-postgres which essentially opens a glorified psql
   session, but does not even support editing the input in
   any "advanced" or just meaningful way; for example, if I
   yank "SELECT 1 + \n2;\n" into the buffer, the "2;" does
   not get prefixed with the continuation prompt, I then
   have to press RET twice to get the result, and the prompt
   is totally gone.

   But even if that stuff would work, it would still not
   provide the clean slate I get with my approach: These are
   the steps to execute on a known state of the database;
   and if they do not "work", the next iteration will start
   again at the known state, not some in-between where some
   functions may have been created/data has been changed
   while others have not.

2. Reading data from the database: These are queries where,
   for example, I'd like to read data from the database to
   set up mail abbreviations.  For simple data, I execute
   "psql -0Atc" and split-string, for more complex struc-
   tures I build a JSON object.  If the query results are
   dependent on some parameter, as there is no
   sql-postgres-quote function and psql does not allow to
   refer in "-c" statements to parameters set with "-v", I
   add an inline Perl script that uses DBI to connect to and
   pass @ARGV to the server and return the results.

3. Writing data to the database: These are queries where I
   want to store data, either single tuples or complex
   structures.  Here again I use an inline Perl script that
   uses DBI to connect to the database and do all the neces-
   sary transaction handling, escaping and sanity checks.

   For very simple queries it feels possible to create a new
   sql-postgres connection, send the query with
   sql-send-string and then check whether the "last" answer
   was "INSERT 0 1" or something like that, but even so the
   buffer looks like a mess because there is no context for
   the answer as the sent query is not printed (yes, there
   is "\set ECHO queries", but it does not necessarily in-
   spire confidence).

As an alternative to 2. and 3., I'm aware of three approach-
es:

a) Speaking natively with the PostgreSQL server from Emacs
   Lisp (https://github.com/cbbrowne/pg.el): This does not
   work with PostgreSQL versions currently supported.

b) Wrapping libpq in an Emacs module
   (https://github.com/anse1/emacs-libpq): This looks (very)
   promising, but requires to compile and install yet anoth-
   er binary (and keep it working with Emacs and PostgreSQL
   versions increasing).

c) EmacsSQL (https://github.com/skeeto/emacsql): This is
   probably the most interesting approach, however instead
   of using standard SQL which I have mastered reasonably
   well and can also reuse in Perl, Python and whatever, it
   comes up with a similar, but different syntax, and more
   complex queries (checking the number of affected rows,
   etc.) do not seem be supported (CMIIW).

None of these feel superior enough to my inline Perl scripts
to warrant the effort of a rewrite.

What do other users use to work on PostgreSQL databases from
Emacs?

Tim




^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Interacting with PostgreSQL
  2020-11-21 23:51 Interacting with PostgreSQL Tim Landscheidt
@ 2020-11-22  1:33 ` Jean Louis
  2020-11-24 23:14   ` Tim Landscheidt
  2020-11-22 21:33 ` Marcin Borkowski
  1 sibling, 1 reply; 13+ messages in thread
From: Jean Louis @ 2020-11-22  1:33 UTC (permalink / raw)
  To: Tim Landscheidt; +Cc: help-gnu-emacs

[-- Attachment #1: Type: text/plain, Size: 9732 bytes --]

Hello Tim,

At least somebody there who works with PostgreSQL.

I was using pg.el before until PostgreSQL upgrade arrived where nobody
could repair or do something, so pg.el stopped working and then I've
discovered `emacs-libpq` and since then use dynamic module. There is
nothing complicated with it. I am attaching my basic file, few of
generic functions I am using mostly with it. And I recommend you using
`emacs-libpq`.

* Tim Landscheidt <tim@tim-landscheidt.de> [2020-11-22 02:52]:
> I've been using Emacs with PostgreSQL for a bit more than
> 20 years now, and every now and then I look at Emacs's SQL
> "stuff" and think that I'm doing something absurdly wrong,
> but can never find a better solution.  So I'd like to pre-
> sent you with three scenarios, my tried and tested workflow
> for each of them and ask for your input on solving them more
> Emacsily.
> 
> 1. Mass data and structure changes: These are changes where
>    I'd like to see the result or test triggers & Co. before
>    committing them.  For that, I have a function to create a
>    scratch buffer for SQL commands in a transaction:
> 
>    | (defun tl-sql-scratch nil
>    |   "Create a scratch buffer for PostgreSQL."
>    |   (interactive)
>    |   (switch-to-buffer (generate-new-buffer "scratch.sql"))
>    |   (sql-mode)
>    |   (sql-highlight-postgres-keywords)
>    |   (insert "BEGIN WORK;\n-- COMMIT WORK;\n")
>    |   (forward-line -1))
> 
>    and set [f12] to pipe the buffer's contents to psql:

When developing SQL tables or wish to do some direct maintenance with
the database, I do {M-x sql-postgres RET} and I am inside.

When developing SQL tables, I open my SQL file like `something.sql`
then I set SQLi buffer from menu I can send paragraphs or regions to
PostgreSQL from there, it is similar like Lisp interactivity.

>    |      "/usr/bin/psql")))
> 
>    I then add UPDATEs, CREATE FUNCTIONs, test cases, etc.,
>    press [f12] until I am satisfied with the results, remove
>    the test cases, uncomment the COMMIT and then press [f12]
>    for the last time before killing the buffer.

Sounds complicated to me. If I want direct interactivity then I just
do {M-x sql-postgres RET} and from inside I use \e or \ev or \ef to
create some functions or change views, etc.

emacsclient is opening within Emacs, when I kill it, SQL is
executed. I do not use any self made functions to interact with
Emacs.

>    The closest replacement for that that I have come across
>    is sql-postgres which essentially opens a glorified psql
>    session, but does not even support editing the input in
>    any "advanced" or just meaningful way; for example, if I
>    yank "SELECT 1 + \n2;\n" into the buffer, the "2;" does
>    not get prefixed with the continuation prompt, I then
>    have to press RET twice to get the result, and the prompt
>    is totally gone.

That may be. I am not worried about it. 

> 2. Reading data from the database: These are queries where,
>    for example, I'd like to read data from the database to
>    set up mail abbreviations.  For simple data, I execute
>    "psql -0Atc" and split-string, for more complex struc-
>    tures I build a JSON object.  If the query results are
>    dependent on some parameter, as there is no
>    sql-postgres-quote function and psql does not allow to
>    refer in "-c" statements to parameters set with "-v", I
>    add an inline Perl script that uses DBI to connect to and
>    pass @ARGV to the server and return the results.

Since I have switched from Perl to Emacs Lisp I do everything in Emacs
Lisp. I have not get same use case as you. I do functions in Emacs
Lisp and database editing within Emacs as interface.

> 3. Writing data to the database: These are queries where I
>    want to store data, either single tuples or complex
>    structures.  Here again I use an inline Perl script that
>    uses DBI to connect to the database and do all the neces-
>    sary transaction handling, escaping and sanity checks.

Ha, alright, but not quite. Why use two programming languages when one
is enough. Somehow complex. Some people like it.

What escaping you need?

I am using this escaping function:

(defun sql-escape-string (str)
  "Returnes escaped string for PostgreSQL. If string is `NULL' returns `NULL'"
  (if (null str)
      (setq str "NULL")
    (when (or (string-match "\\\\" str)
              (string-match "'" str))
      (setq str (replace-regexp-in-string "\\\\" "\\\\\\\\" str))
      (setq str (replace-regexp-in-string "'" "''" str))))
  (unless (string= "NULL" str)
    (setq str (format "E'%s'" str)))
  str)

Maybe I am missing something but so far in last year I did not have
any incident for using this escaping.

>    For very simple queries it feels possible to create a new
>    sql-postgres connection, send the query with
>    sql-send-string and then check whether the "last" answer
>    was "INSERT 0 1" or something like that, but even so the
>    buffer looks like a mess because there is no context for
>    the answer as the sent query is not printed (yes, there
>    is "\set ECHO queries", but it does not necessarily in-
>    spire confidence).

That means it is done. I like using "RETURNING table_id" to get the
value of the new entry immediately and act upon it. Very little stuff
I do directly in psql. That is when I need to design tables so I write
it in the file and send to sql-postgres buffer inside of Emacs.

All other database editing, adding entries, deleting is done through
Emacs, for example listing entries I do in tabulated-list-mode, or I
am using helm-mode or ivy-mode to find entry and edit in Emacs
straight. 

> a) Speaking natively with the PostgreSQL server from Emacs
>    Lisp (https://github.com/cbbrowne/pg.el): This does not
>    work with PostgreSQL versions currently supported.

Exactly, forget it. I will never use it again.

> b) Wrapping libpq in an Emacs module
>    (https://github.com/anse1/emacs-libpq): This looks (very)
>    promising, but requires to compile and install yet anoth-
>    er binary (and keep it working with Emacs and PostgreSQL
>    versions increasing).

That is not hard to do and when compiled it simply works. That is my
best choice. Just use this and forget other stuff. I am using Emacs
development version and I do not think of re-compiling that
module. Developers will soon include it in GNU ELPA which is great
thing. It will help so many people to manage information.

> c) EmacsSQL (https://github.com/skeeto/emacsql): This is
>    probably the most interesting approach, however instead
>    of using standard SQL which I have mastered reasonably
>    well and can also reuse in Perl, Python and whatever, it
>    comes up with a similar, but different syntax, and more
>    complex queries (checking the number of affected rows,
>    etc.) do not seem be supported (CMIIW).

It may look nice to you, to me it looks dependable:

> (emacsql db [:create-table people ([name id salary])])

> ;; Or optionally provide column constraints.
> (emacsql db [:create-table people
>              ([name (id integer :primary-key) (salary float)])])

I don't like that as it is not SQL to me. So I have no freedom
there. It looks as hard coded idiosyncratic structure to which I do
not wish to depend for future.

I like writing functions myself and understanding it.

(defun rcd-db-column-comment (table column pg)
  (let ((sql (format "SELECT pgd.description FROM pg_catalog.pg_statio_all_tables AS st INNER JOIN pg_catalog.pg_description pgd ON (pgd.objoid=st.relid) INNER JOIN information_schema.columns c ON (pgd.objsubid=c.ordinal_position AND c.table_schema=st.schemaname AND c.table_name=st.relname AND c.table_name = '%s' AND c.table_schema = 'public' AND c.column_name = '%s')" table column)))
    (rcd-sql-first sql pg)))

I would spend way too much time understanding how to translate already
to me complex SQL to that structure. Unless I am ready to submit to
mortification of flesh I will never use that EmacsSQL.

Ah just do it yourself how you think is better.

My tables are made so that each table has its _id as unique id. This
makes it then handy to construct such function:

(defun rcd-db-get-entry (table column id pg)
  "Returns value for the column from the RCD Database by using the entry ID"
  (let* ((sql (format "SELECT %s FROM %s WHERE %s_id = %s" column table table id))
	 (value (rcd-sql-first sql pg)))
    value))

You could call it `db-get`

(db-get "contacts" "get_contacts_name(contacts_id)" 123 *pg-handle*)

or

(db-get "countrie" "countries_phoneprefix" 217 *pg-handle*)

or like this:

(defun db-delete-entry (table id pg)
  "Delets entry by its ID without cascading"
  (let ((sql (format "DELETE FROM %s WHERE %s_id = %s" table table id)))
    (rcd-sql sql pg)))

Let us say you find contact Tim in your index, and you wish to delete
it, invoke db-delete-entry (db-delete-entry "contacts" 123 *handle*)

Of course those are underlying functions, your Emacs should ask you if
to delete or not. I am deleting everything relating to some contacts.

I have bunch of functions and I think there is nothing that cannot be
done with Emacs Lisp directly.

> None of these feel superior enough to my inline Perl scripts to
> warrant the effort of a rewrite.

Well... what to say. I also have Perl scripts from before and I use it
with other programs without thinking about it.

For example I press F9 in Mutt and it will check if contact is in the
database or not, then I choose where to sort the contact.

> What do other users use to work on PostgreSQL databases from Emacs?

`emacs-libpq` is best choice and will remain so for long time. It
offers all liberties and is faster.

Let me know more what you do with PostgreSQL.

Jean

[-- Attachment #2: rcd-db-init.el --]
[-- Type: text/plain, Size: 6220 bytes --]

;;; rcd-db-init.el --- RCD Database Initialization and basic SQL query functions

;; Copyright (C) 2016-2020 by Jean Louis

;; Author: Jean Louis <bugs@gnu.support>
;; Version: 1.7
;; Package-Requires: 
;; Keywords: applications
;; URL: https://gnu.support/gnu-emacs/packages/rcd-db-init-el.html

;; This file is not part of GNU Emacs.

;; This program is free software: you can redistribute it and/or
;; modify it under the terms of the GNU General Public License as
;; published by the Free Software Foundation, either version 3 of the
;; License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful, but
;; WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;; General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.

;;; Commentary:

;; RCD Database Initialization and basic SQL query functions uses
;; PostgreSQL database backend. This may change in future to use any
;; other type of a database.
;;
;; RCD is acronym for Reach, Connect, Deliver, my personal
;; principle and formula for Wealth.

;;; Change Log:

;;; Code:

;; TODO remove the following line when emacs-libpq becomes part of GNU ELPA
(add-to-list 'load-path "~/Programming/git/emacs-libpq/")

(require 'pq)

(defun rcd-db-connect (database &optional port host username password)
  "Connects to PostgreSQL database with specified parameters, by
using the GNU Emacs module emasc-libpq"
  (let* ((port (if port port 5432))
	 (connection (format "dbname=%s port=%s" database port))
	 (connection (if host
			 (concat connection (format " host=%s" host))
		       connection))
	 (connection (if username
			 (concat connection (format " user=%s" username))
		       connection))
	 (connection (if password
			 (concat connection (format " password=%s" password))
		       connection))
	 (connection (or (getenv "PG_CONNINFO") connection)))
    (pq:connectdb connection)))

(defun rcd-sql (sql pg)
  "Sends SQL queries to PostgreSQL database and returns results"
    (condition-case err
	(pq:query pg sql)
      (error
       (if (string-match "^ERROR:  syntax error" (cdr err))
	   (progn
	     (if (fboundp 'speak) (speak (cdr err)))
	     (message (cdr err)))
	 ;; re-throw
	 (signal (car err) (cdr err))))))

(defun rcd-sql-list (sql pg)
  "Returns list of lists instead of vectors"
  (let ((list '()))
    (dolist (i (apply 'rcd-sql (list sql pg)) (reverse list))
      (cond ((eq (type-of i) 'vector) (push (append i '()) list))
	    (t (push i list))))))

(defun rcd-sql-first (sql pg)
  "Returns first entry from SQL query"
  (car (apply 'rcd-sql (list sql pg))))

(defun rcd-sql-list-first (sql pg)
  "Returns first item of the list of lists instead of vectors"
  ;; TODO this is not verified that it works well as intended
  (let ((list (rcd-sql-first sql pg)))
    (append list '())))

(define-skeleton cf-sql-table
    "Prepare the SQL table for Central Files database design"
  nil
  "
-- ------------------------------------------
-- ------------ Table " (setq table (skeleton-read "Table name: ")) "
-- ------------------------------------------
DROP SEQUENCE " table "_id_seq;

CREATE TABLE " table " (
" table "_id SERIAL NOT NULL PRIMARY KEY,
" table "_datecreated TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
" table "_datemodified TIMESTAMP,
" table "_usercreated TEXT NOT NULL DEFAULT current_user,
" table "_usermodified TEXT NOT NULL DEFAULT current_user,
" table "_name TEXT,
" table "_title TEXT,
" table "_description TEXT,
" table "_ TEXT
);
GRANT ALL ON " table " TO PUBLIC;
DROP VIEW " table "_combo;
CREATE OR REPLACE VIEW " table "_combo AS
SELECT " table "_id AS id,
" table "_name AS TEXT
FROM " table ";
GRANT SELECT ON " table "_combo TO PUBLIC;

DROP VIEW " table "_rcd;
CREATE OR REPLACE VIEW " table "_rcd AS
SELECT concat(" table "_id, ' '," table "_name) AS id
FROM " table ";
GRANT SELECT ON " table "_rcd TO PUBLIC;

COMMENT ON TABLE " table " IS '" (capitalize table) "';
COMMENT ON COLUMN " table "." table "_id IS 'ID';
COMMENT ON COLUMN " table "." table "_datecreated IS 'Date created';
COMMENT ON COLUMN " table "." table "_datemodified IS 'Date modified';
COMMENT ON COLUMN " table "." table "_usercreated IS 'User created';
COMMENT ON COLUMN " table "." table "_usermodified IS 'User modified';
COMMENT ON COLUMN " table "." table "_hid IS 'HID';
COMMENT ON COLUMN " table "." table "_name IS 'Name';
COMMENT ON COLUMN " table "." table "_title IS 'Title';
COMMENT ON COLUMN " table "." table "_description IS 'Description';
COMMENT ON COLUMN " table "." table "_IS '';

CREATE UNIQUE INDEX " table "_index ON " table " ( " table "_weekend );

INSERT INTO meta_fields VALUES ('" table "','" table "_description','widget','area(rows=10,cols=60)');
INSERT INTO meta_fields VALUES ('" table "','" table "_datecreated','widget','readonly');
INSERT INTO meta_fields VALUES ('" table "','" table "_datemodified','widget','readonly');
INSERT INTO meta_fields VALUES ('" table "','" table "_usercreated','widget','readonly');
INSERT INTO meta_fields VALUES ('" table "','" table "_usermodified','widget','readonly');
INSERT INTO meta_fields VALUES ('" table "','" table "_','hide_list','1');
-- INSERT INTO " table " (" table "_name) VALUES ('');
-- INSERT INTO meta_tables VALUES ('" table "', 'hide', '1');

-- Triggers
-- For Date Modified
CREATE TRIGGER " table "_moddatetime
BEFORE UPDATE ON " table "
FOR EACH ROW
EXECUTE PROCEDURE moddatetime(" table "_datemodified);

-- For User Modified
CREATE TRIGGER insert_username_" table "
BEFORE INSERT OR UPDATE ON " table "
FOR EACH ROW
EXECUTE PROCEDURE insert_username(" table "_usermodified);


-- List view
/*
DROP VIEW " table "_list;
CREATE OR REPLACE VIEW " table "_list AS
SELECT " table "_id, " table "_name
FROM " table " ORDER BY " table "_id DESC;
COMMENT ON VIEW " table "_list IS '" (capitalize table) "';
COMMENT ON COLUMN " table "_list." table "_id IS 'ID';
COMMENT ON COLUMN " table "_list." table "_name IS 'Name'; 
*/
}
);")

(provide 'rcd-db-init)

;;; rcd-db-init.el ends here

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Interacting with PostgreSQL
  2020-11-21 23:51 Interacting with PostgreSQL Tim Landscheidt
  2020-11-22  1:33 ` Jean Louis
@ 2020-11-22 21:33 ` Marcin Borkowski
  2020-11-24 20:42   ` Tim Landscheidt
  2020-11-27  2:01   ` Jean Louis
  1 sibling, 2 replies; 13+ messages in thread
From: Marcin Borkowski @ 2020-11-22 21:33 UTC (permalink / raw)
  To: Tim Landscheidt; +Cc: help-gnu-emacs

Hi there,

not sure if this will help, but I sometimes use Org-mode to interact
with Postgres:
http://mbork.pl/2020-03-09_Using_Org-mode_as_a_PostgreSQL_client

Best,
Marcin

On 2020-11-22, at 00:51, Tim Landscheidt <tim@tim-landscheidt.de> wrote:

> Hi,
>
> I've been using Emacs with PostgreSQL for a bit more than
> 20 years now, and every now and then I look at Emacs's SQL
> "stuff" and think that I'm doing something absurdly wrong,
> but can never find a better solution.  So I'd like to pre-
> sent you with three scenarios, my tried and tested workflow
> for each of them and ask for your input on solving them more
> Emacsily.
>
> 1. Mass data and structure changes: These are changes where
>    I'd like to see the result or test triggers & Co. before
>    committing them.  For that, I have a function to create a
>    scratch buffer for SQL commands in a transaction:
>
>    | (defun tl-sql-scratch nil
>    |   "Create a scratch buffer for PostgreSQL."
>    |   (interactive)
>    |   (switch-to-buffer (generate-new-buffer "scratch.sql"))
>    |   (sql-mode)
>    |   (sql-highlight-postgres-keywords)
>    |   (insert "BEGIN WORK;\n-- COMMIT WORK;\n")
>    |   (forward-line -1))
>
>    and set [f12] to pipe the buffer's contents to psql:
>
>    | (define-key sql-mode-map
>    |   [f12]
>    |   (lambda nil
>    |     (interactive)
>    |     (shell-command-on-region
>    |      (point-min)
>    |      (point-max)
>    |      "/usr/bin/psql")))
>
>    I then add UPDATEs, CREATE FUNCTIONs, test cases, etc.,
>    press [f12] until I am satisfied with the results, remove
>    the test cases, uncomment the COMMIT and then press [f12]
>    for the last time before killing the buffer.
>
>    The closest replacement for that that I have come across
>    is sql-postgres which essentially opens a glorified psql
>    session, but does not even support editing the input in
>    any "advanced" or just meaningful way; for example, if I
>    yank "SELECT 1 + \n2;\n" into the buffer, the "2;" does
>    not get prefixed with the continuation prompt, I then
>    have to press RET twice to get the result, and the prompt
>    is totally gone.
>
>    But even if that stuff would work, it would still not
>    provide the clean slate I get with my approach: These are
>    the steps to execute on a known state of the database;
>    and if they do not "work", the next iteration will start
>    again at the known state, not some in-between where some
>    functions may have been created/data has been changed
>    while others have not.
>
> 2. Reading data from the database: These are queries where,
>    for example, I'd like to read data from the database to
>    set up mail abbreviations.  For simple data, I execute
>    "psql -0Atc" and split-string, for more complex struc-
>    tures I build a JSON object.  If the query results are
>    dependent on some parameter, as there is no
>    sql-postgres-quote function and psql does not allow to
>    refer in "-c" statements to parameters set with "-v", I
>    add an inline Perl script that uses DBI to connect to and
>    pass @ARGV to the server and return the results.
>
> 3. Writing data to the database: These are queries where I
>    want to store data, either single tuples or complex
>    structures.  Here again I use an inline Perl script that
>    uses DBI to connect to the database and do all the neces-
>    sary transaction handling, escaping and sanity checks.
>
>    For very simple queries it feels possible to create a new
>    sql-postgres connection, send the query with
>    sql-send-string and then check whether the "last" answer
>    was "INSERT 0 1" or something like that, but even so the
>    buffer looks like a mess because there is no context for
>    the answer as the sent query is not printed (yes, there
>    is "\set ECHO queries", but it does not necessarily in-
>    spire confidence).
>
> As an alternative to 2. and 3., I'm aware of three approach-
> es:
>
> a) Speaking natively with the PostgreSQL server from Emacs
>    Lisp (https://github.com/cbbrowne/pg.el): This does not
>    work with PostgreSQL versions currently supported.
>
> b) Wrapping libpq in an Emacs module
>    (https://github.com/anse1/emacs-libpq): This looks (very)
>    promising, but requires to compile and install yet anoth-
>    er binary (and keep it working with Emacs and PostgreSQL
>    versions increasing).
>
> c) EmacsSQL (https://github.com/skeeto/emacsql): This is
>    probably the most interesting approach, however instead
>    of using standard SQL which I have mastered reasonably
>    well and can also reuse in Perl, Python and whatever, it
>    comes up with a similar, but different syntax, and more
>    complex queries (checking the number of affected rows,
>    etc.) do not seem be supported (CMIIW).
>
> None of these feel superior enough to my inline Perl scripts
> to warrant the effort of a rewrite.
>
> What do other users use to work on PostgreSQL databases from
> Emacs?
>
> Tim


-- 
Marcin Borkowski
http://mbork.pl



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Interacting with PostgreSQL
  2020-11-22 21:33 ` Marcin Borkowski
@ 2020-11-24 20:42   ` Tim Landscheidt
  2020-11-27  2:01   ` Jean Louis
  1 sibling, 0 replies; 13+ messages in thread
From: Tim Landscheidt @ 2020-11-24 20:42 UTC (permalink / raw)
  To: help-gnu-emacs

Marcin Borkowski <mbork@mbork.pl> wrote:

> not sure if this will help, but I sometimes use Org-mode to interact
> with Postgres:
> http://mbork.pl/2020-03-09_Using_Org-mode_as_a_PostgreSQL_client

> […]

I sometimes do as well, mainly for read-only queries, and it
has the very incentive benefit that one can add a bunch of
DONE tasks to the daily agenda view :-).  But for data mung-
ing I have two reservations:

- AFAICT, there is no way to execute the code block while
  editing.  So I have to either C-c ', edit, C-c ', C-c C-c,
  check the result, lather, rinse, repeat, finally uncomment
  COMMIT and C-c C-c, or edit the query "inline" which can
  be dangerous when pasting bulk data or replacing text be-
  cause it is easy to miss where the query ends.

- For non-idempotent queries (say, incrementing a column
  once for all rows), there are no safeguards against acci-
  dentally re-executing the query in the future.  So I would
  have to edit the query and evaluate the code block for
  testing, then uncomment the COMMIT, evaluate the code
  block, then comment the COMMIT again to be on the safe
  side.

Tim

P. S.: Just noticed that apparently :prologue and :epilogue
       are ignored in ob-sql.  I'll file a report for that.




^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Interacting with PostgreSQL
  2020-11-22  1:33 ` Jean Louis
@ 2020-11-24 23:14   ` Tim Landscheidt
  2020-11-25  4:18     ` Jean Louis
  0 siblings, 1 reply; 13+ messages in thread
From: Tim Landscheidt @ 2020-11-24 23:14 UTC (permalink / raw)
  To: help-gnu-emacs

Jean Louis <bugs@gnu.support> wrote:

> […]

>>    |      "/usr/bin/psql")))

>>    I then add UPDATEs, CREATE FUNCTIONs, test cases, etc.,
>>    press [f12] until I am satisfied with the results, remove
>>    the test cases, uncomment the COMMIT and then press [f12]
>>    for the last time before killing the buffer.

> Sounds complicated to me. If I want direct interactivity then I just
> do {M-x sql-postgres RET} and from inside I use \e or \ev or \ef to
> create some functions or change views, etc.

> emacsclient is opening within Emacs, when I kill it, SQL is
> executed. I do not use any self made functions to interact with
> Emacs.

As a mere mortal :-), when for example I add triggers to
five tables with three test cases (INSERT, UPDATE, DELETE)
each, I will not remember which of the triggers or test
cases have been set/inserted/updated/deleted.  Also, my mind
will be focussed on fixing the functions/etc.  Worst case is
that I miss that psql has reverted to auto-commit mode and
my not-yet-working trigger/query overwrites good data with
garbage.

So I definitely want to be sure that my changes are (easily)
revertable until they are working properly.

> […]

>> 3. Writing data to the database: These are queries where I
>>    want to store data, either single tuples or complex
>>    structures.  Here again I use an inline Perl script that
>>    uses DBI to connect to the database and do all the neces-
>>    sary transaction handling, escaping and sanity checks.

> Ha, alright, but not quite. Why use two programming languages when one
> is enough. Somehow complex. Some people like it.

For the same reason why I use PostgreSQL to store data and
not Emacs :-).  It is highly unlikely that call-process and
Perl's DBI change in a fundamental way anytime soon, and if
they did, there would probably be millions of users explain-
ing how to migrate to a new system.

> What escaping you need?

> I am using this escaping function:

> (defun sql-escape-string (str)
>   "Returnes escaped string for PostgreSQL. If string is `NULL' returns `NULL'"
>   (if (null str)
>       (setq str "NULL")
>     (when (or (string-match "\\\\" str)
>               (string-match "'" str))
>       (setq str (replace-regexp-in-string "\\\\" "\\\\\\\\" str))
>       (setq str (replace-regexp-in-string "'" "''" str))))
>   (unless (string= "NULL" str)
>     (setq str (format "E'%s'" str)))
>   str)

> Maybe I am missing something but so far in last year I did not have
> any incident for using this escaping.

> […]

I prefer to use shell-quote-argument and other prebaked
functions because "did not break yet" means that there is a
chance that I will discover at 3 AM that my data has been
garbled, and now I would have to find the error in my quote
function, fix all the data that has been trashed, and do all
that under time pressure because I have a deadline at 4 AM.
So if I have a working solution with call-process and DBI
that is partially tested every day by millions of users, I
rather not replace just for the sake of replacing it.

Tim




^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Interacting with PostgreSQL
  2020-11-24 23:14   ` Tim Landscheidt
@ 2020-11-25  4:18     ` Jean Louis
  2020-11-25 10:37       ` Tim Landscheidt
  0 siblings, 1 reply; 13+ messages in thread
From: Jean Louis @ 2020-11-25  4:18 UTC (permalink / raw)
  To: Tim Landscheidt; +Cc: help-gnu-emacs

* Tim Landscheidt <tim@tim-landscheidt.de> [2020-11-25 02:15]:
> As a mere mortal :-), when for example I add triggers to
> five tables with three test cases (INSERT, UPDATE, DELETE)
> each, I will not remember which of the triggers or test
> cases have been set/inserted/updated/deleted.

Thank you.

I am probably not getting it right. I got impression that when I set
triggers to work they are set to be forgotten and I do not need to
think of it any more.

In general I am developing SQL in the SQL file, so anything I do I
write first in the file. Rarely I will go to sql-postgres to change
some view or similar.

Better workflow is always writing it first in the file and then
executing chunks from file. It is just fine for testing. Benefit is
that I can recreate new database from the file that has much better
readability then the SQL dump.

> Also, my mind will be focussed on fixing the functions/etc.  Worst
> case is that I miss that psql has reverted to auto-commit mode and
> my not-yet-working trigger/query overwrites good data with garbage.

OK, I do not know about that. And I am not using auto commit mode, did
not know that it exists and will not switch to it.

> So I definitely want to be sure that my changes are (easily)
> revertable until they are working properly.

Quite understandable. I did not encounter similar problems in last so
many years.

> I prefer to use shell-quote-argument and other prebaked
> functions because "did not break yet" means that there is a
> chance that I will discover at 3 AM that my data has been
> garbled, and now I would have to find the error in my quote
> function, fix all the data that has been trashed, and do all
> that under time pressure because I have a deadline at 4 AM.

I said "did not break yet" as the function is escaping the quotes,
maybe backslashes, and I do not remember now if there is anything else
to be escaped really. That function did not break ever is also the
case. When it is there you can inspect it and look into specification
and then make test cases and see if it works well or not.

I am sure that Perl has also somewhere SQL escaping functions and it
also has bugs, so there is not much difference. PostgreSQL has also
bugs, programmers are not perfect.

I have used this function in Perl.

sub sql_escape ($) {
	my ($self, $string) = @_;
	return unless $string;
	$string =~ s/'/''/g;
	$string =~ s/\\/\\\\/g;
	return $string;
}

> So if I have a working solution with call-process and DBI
> that is partially tested every day by millions of users, I
> rather not replace just for the sake of replacing it.

Hm, yes and no. Good when you are familiar with it. My side I like to
interact with Emacs Lisp directly to be kind of free of Perl.

I am interested in your work.

What do you store in the database?

Do you interact through Emacs with it?




^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Interacting with PostgreSQL
  2020-11-25  4:18     ` Jean Louis
@ 2020-11-25 10:37       ` Tim Landscheidt
  2020-11-25 14:25         ` Jean Louis
  0 siblings, 1 reply; 13+ messages in thread
From: Tim Landscheidt @ 2020-11-25 10:37 UTC (permalink / raw)
  To: help-gnu-emacs

Jean Louis <bugs@gnu.support> wrote:

> […]

>> Also, my mind will be focussed on fixing the functions/etc.  Worst
>> case is that I miss that psql has reverted to auto-commit mode and
>> my not-yet-working trigger/query overwrites good data with garbage.

> OK, I do not know about that. And I am not using auto commit mode, did
> not know that it exists and will not switch to it.

The problem is that you do not need to consciously use auto-
commit mode, but that psql automatically reverts to it when
you rollback or commit a transaction:

| tim=> BEGIN WORK;
| BEGIN
| tim=> INSERT INTO t (ID) VALUES (1);
| INSERT 0 1
| tim=> ROLLBACK WORK;
| ROLLBACK
| tim=> INSERT INTO t (ID) VALUES (1);
| INSERT 0 1
| tim=> -- The row has been committed.

You can set the AUTOCOMMIT variable to off, but that does
not turn auto-commit off, but instead silently inserts BEGIN
statements where psql thinks they are useful; it can also
interfere with scripts that except auto-commit to be on.

> […]

> I am interested in your work.

> What do you store in the database?

> Do you interact through Emacs with it?

Yes, that was the point of my question :-).  I use Postgre-
SQL to store most data that fits a relational model and (for
a huge part) use Emacs to interact with it.  I also use a
number of Perl scripts for daily consistency checks and
other Perl/Python scripts where either the input/output will
be part of a pipeline or there is a modal UI that I do not
(yet) have the motivation to rewrite in Emacs Lisp (e. g.,
playing a podcast in the background and "afterwards" asking
the user whether the podcast should be marked as "heard" and
then update the database accordingly before archiving/delet-
ing the podcast file).

Tim




^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Interacting with PostgreSQL
  2020-11-25 10:37       ` Tim Landscheidt
@ 2020-11-25 14:25         ` Jean Louis
  2020-11-25 17:08           ` Tim Landscheidt
  0 siblings, 1 reply; 13+ messages in thread
From: Jean Louis @ 2020-11-25 14:25 UTC (permalink / raw)
  To: Tim Landscheidt; +Cc: help-gnu-emacs

* Tim Landscheidt <tim@tim-landscheidt.de> [2020-11-25 13:38]:
> The problem is that you do not need to consciously use auto-
> commit mode, but that psql automatically reverts to it when
> you rollback or commit a transaction:
> 
> | tim=> BEGIN WORK;
> | BEGIN
> | tim=> INSERT INTO t (ID) VALUES (1);
> | INSERT 0 1
> | tim=> ROLLBACK WORK;
> | ROLLBACK
> | tim=> INSERT INTO t (ID) VALUES (1);
> | INSERT 0 1
> | tim=> -- The row has been committed.

I understand. I always used it manually and will rather continue. Just
observing how you do it.

> > I am interested in your work.
> 
> > What do you store in the database?
> 
> > Do you interact through Emacs with it?
> 
> Yes, that was the point of my question :-).  I use Postgre-
> SQL to store most data that fits a relational model and (for
> a huge part) use Emacs to interact with it.  I also use a
> number of Perl scripts for daily consistency checks and
> other Perl/Python scripts where either the input/output will
> be part of a pipeline or there is a modal UI that I do not
> (yet) have the motivation to rewrite in Emacs Lisp (e. g.,
> playing a podcast in the background and "afterwards" asking
> the user whether the podcast should be marked as "heard" and
> then update the database accordingly before archiving/delet-
> ing the podcast file).

That is some type of logging or recording, I understand.

Any time I need some structured and relational data I use
PostgreSQL. For example to insert geographic locations of interests
that are helpful to other people or coordinates of lands. When
coordinates are in the database then I can invoke map downloads with
nicely shown lands on the geographic map.

In general I use database for everything including for sorting files
by using database where program decides where files are sorted not me,
for quick retrieval of files where program decides it, for SMS record,
phone calls, notes, project planning, Website Revision System,
variables for the WRS.

It helps in preparing translations, I can just write some words into
database then I run program that fetches automatic translations and
translates it before human makes the review of it.

Also for website forms, like all those small pieces of HTML like text
inputs, check boxes and similar. When there is a lot of work that
becomes simple reuse without much copy/paste or looking into files.

Then for invoices, for reporting and records of all kinds, reminders,
real estate agency, opportunities, market pricing, statistics, just
for anything that requires structure and relations.

Do you use any kind of revision system?

I have made recently my own revision system, you can see the simple
table below, and `hyperscope-vc' that fetches values and inserts into
the "version control" table.

Then function like `hlink-edit-org' with `hyperscope-vc' before the
update makes sure that information first get recorded in the version
control table. I could as well record all updates that I do through
Emacs and it could be possible to make triggers as well, but I like it
this way now.

If you know other ways of version control, let me know.

(defun hlink-edit-org (id)
  (let* ((blob (hlink-description-value id))
	 (blob (if blob blob  ""))
	 (buffer-name (format "HyperScope Editing ID: %d" id))
	 (new-blob (read-from-buffer blob buffer-name 'org-mode)))
    (hyperscope-vc "hlinks" "hlinks_description" id)
    (rcd-db-update-entry "hlinks" "hlinks_description" "text" id new-blob *hs*)))

(defun hyperscope-vc (table column id &optional description)
  "Simple version system."
  (let* ((value (rcd-db-get-entry table column id *hs*))
	 (value (sql-escape-string value)) ;; TODO only text supported for now
	 (description (if description (sql-escape-string description) "NULL"))
	 (sql (format "INSERT INTO vc (vc_table, 
                                      vc_column, 
                                      vc_tableid, 
                                      vc_value, 
                                      vc_description) VALUES ('%s', '%s', %s, %s, %s)
                         RETURNING vc_id"
		      table column id value description))
	 (id (rcd-sql sql *hs*)))
    (if id id nil)))

CREATE TABLE vc (
vc_id SERIAL NOT NULL PRIMARY KEY,
vc_datecreated TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
vc_datemodified TIMESTAMP,
vc_usercreated TEXT NOT NULL DEFAULT current_user,
vc_usermodified TEXT NOT NULL DEFAULT current_user,
vc_table TEXT NOT NULL,
vc_column TEXT NOT NULL,
vc_tableid INT4 NOT NULL,
vc_value TEXT 
);



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Interacting with PostgreSQL
  2020-11-25 14:25         ` Jean Louis
@ 2020-11-25 17:08           ` Tim Landscheidt
  2020-11-27  1:40             ` Jean Louis
  0 siblings, 1 reply; 13+ messages in thread
From: Tim Landscheidt @ 2020-11-25 17:08 UTC (permalink / raw)
  To: help-gnu-emacs

Jean Louis <bugs@gnu.support> wrote:

>> The problem is that you do not need to consciously use auto-
>> commit mode, but that psql automatically reverts to it when
>> you rollback or commit a transaction:

>> | tim=> BEGIN WORK;
>> | BEGIN
>> | tim=> INSERT INTO t (ID) VALUES (1);
>> | INSERT 0 1
>> | tim=> ROLLBACK WORK;
>> | ROLLBACK
>> | tim=> INSERT INTO t (ID) VALUES (1);
>> | INSERT 0 1
>> | tim=> -- The row has been committed.

> I understand. I always used it manually and will rather continue. Just
> observing how you do it.

Eh, that /is/ the behaviour using it manually, either on the
command line or via sql-postgres.

> […]

> Do you use any kind of revision system?

> I have made recently my own revision system, you can see the simple
> table below, and `hyperscope-vc' that fetches values and inserts into
> the "version control" table.

> […]

> If you know other ways of version control, let me know.

> […]

If I were to choose a system for storing structured informa-
tion, I would almost certainly not use a system that accord-
ing to https://github.com/BradNeuberg/hyperscope (last up-
dated six years ago) "is not currently maintained.  It is
present here for archival purposes."

There are org-mode, many markdown variants, plain HTML, and
apparently even a dedicated GNU project called Hyperbole
(https://www.gnu.org/software/hyperbole/).  There are a my-
riad of version control systems, with Git at the forefront.
Most of them are natively supported by Emacs, right out of
the box.

I find that there is a lot of strength in numbers and thus
I like to use software that is used by at least a sizable,
critical mass of other users.  This gives me confidence that
if I encounter a problem, either a bug or just a question of
how to achieve something in the most effective or efficient
way, others will have treaded that path before me and
hopefully left some breadcrumbs.  And if I am genuinely the
first one to tackle an issue, my solution to it will not
only benefit myself, but also others who may face the same
questions.

Tim




^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Interacting with PostgreSQL
  2020-11-25 17:08           ` Tim Landscheidt
@ 2020-11-27  1:40             ` Jean Louis
  2020-11-30  3:12               ` Tim Landscheidt
  0 siblings, 1 reply; 13+ messages in thread
From: Jean Louis @ 2020-11-27  1:40 UTC (permalink / raw)
  To: Tim Landscheidt; +Cc: help-gnu-emacs

* Tim Landscheidt <tim@tim-landscheidt.de> [2020-11-25 20:09]:
> Jean Louis <bugs@gnu.support> wrote:
> 
> >> The problem is that you do not need to consciously use auto-
> >> commit mode, but that psql automatically reverts to it when
> >> you rollback or commit a transaction:
> 
> >> | tim=> BEGIN WORK;
> >> | BEGIN
> >> | tim=> INSERT INTO t (ID) VALUES (1);
> >> | INSERT 0 1
> >> | tim=> ROLLBACK WORK;
> >> | ROLLBACK
> >> | tim=> INSERT INTO t (ID) VALUES (1);
> >> | INSERT 0 1
> >> | tim=> -- The row has been committed.
> 
> > I understand. I always used it manually and will rather continue. Just
> > observing how you do it.
> 
> Eh, that /is/ the behaviour using it manually, either on the
> command line or via sql-postgres.

I understand what you mean. Without BEGIN I am in autocommit
mode. That is standard. But why is it problem for you?

> > Do you use any kind of revision system?
> 
> > I have made recently my own revision system, you can see the simple
> > table below, and `hyperscope-vc' that fetches values and inserts into
> > the "version control" table.
> 
> > […]
> 
> > If you know other ways of version control, let me know.
> 
> > […]
> 
> If I were to choose a system for storing structured informa-
> tion, I would almost certainly not use a system that accord-
> ing to https://github.com/BradNeuberg/hyperscope (last up-
> dated six years ago) "is not currently maintained.  It is
> present here for archival purposes."

I do not think that is related to PostgreSQL, maybe, but I have no
idea. It is not software I am making for Emacs. 

> There are org-mode, many markdown variants, plain HTML, and
> apparently even a dedicated GNU project called Hyperbole
> (https://www.gnu.org/software/hyperbole/).

Definitely yes. But those you mentioned are related only by
having hyperlink features. Org mode is outline mode, markdown is not
quite outline neither hierarchical, it is pre-processor for HTML. GNU
Hyperbole I am using daily and started using it back in time, maybe 2
decades with pauses and never fully used all of the options it
has. Maybe you mean Koutliner in GNU Hyperbole as that is outline
somewhat similar to Org but better structured.

Emacs HyperScope is dynamic knowledge repository that augments
knowledge, relates it together and serves as dynamic knowledge
repository that follows the technology template project for open
hyperdocument systems by Doug Engelbart, definitely similar in its
nature to first Javascript based HyperScope. This one is for Emacs.

About Dynamic Knowledge Repositories (DKR)
https://www.dougengelbart.org/content/view/190/163/

TECHNOLOGY TEMPLATE PROJECT OHS Framework 
https://www.dougengelbart.org/content/view/110/460/

> There are a my- riad of version control systems, with Git at the
> forefront.  Most of them are natively supported by Emacs, right out
> of the box.

That is right. And I need to think about such. For example I would
need to check in, check out, and I do that for the files.

When editing database entries, those are not files on file
system. Data comes from the database. That data is itself stored in
some files that PostgreSQL database manages is irrelevant as user has
no access to source files normally, neither is allowed to do some
versioning with such. Interaction goes over TCP or sockets and not
from file access. In that sense when I am editing for example Org
based data it is not file from file system but Org mode formatted data
then there is currently none known versioning system that I know that
is generic for databases.

This can be easily helped with simple procedure that function that is
about to edit the data simply fetch the edited data and stores it in
the version control table before any editing. Version control table
remembers the table, column ID, column, type and value. Right now I am
storing those as text, but not numbers as it need some type casting to
text that I can implement later. Major problem is with larger text
that requires sometimes longer editing.

Because such editing is without files I would like to know if I could
temporarily assign a disconnected file to buffer so that file get
saved from buffer, but when I finish recursive editing that
buffer-string gets returned to my function that stores it into
database. That is yet unsolved problem and could be solution to safety
of data being edited longer time.

Two safety problems are with PostgreSQL data entry editing, one is to
save the previouse entries or historical and that I have solved in
very simple manner. Other problem is to solve the currently edited
text that is nowhere saved. For that reason I wish to find way to
automatically save the buffers somewhere but not that buffer is
connected to the file being saved.

Does anybody have pointers how to do that?

> I find that there is a lot of strength in numbers and thus
> I like to use software that is used by at least a sizable,
> critical mass of other users.

Well, I program first for me to organize things, then it has
tremendous value for others in my group, and then there is maybe small
value in public when software is published. Without programming I
would never get what I really want as software for what I need does
not exists normally.

If you refer to version control systems, in the above example with
versioning table there is nothing to think of. Once you make function
to fetch data from edited table and save it in versioning table your
function works always. Since I made it before maybe 2-3 days there are
168 entries of all kinds of data. It just works and can work for
years.

> This gives me confidence that if I encounter a problem, either a bug
> or just a question of how to achieve something in the most effective
> or efficient way, others will have treaded that path before me and
> hopefully left some breadcrumbs.  And if I am genuinely the first
> one to tackle an issue, my solution to it will not only benefit
> myself, but also others who may face the same questions.

Yes and no, I do not know how it applies here. PostgreSQL is designed
in such manner that it is left to users how to design their tables and
database. It involves and demands planning, development,
implementation. All what one need is specification of PostgreSQL and
one can build parts one by one until system works well
integrated. Almost any programming language can be used.

In decades I have not encountered any serious problem. If there is
single mistake in the SQL it will simply not work. Isn't that
simplicity very useful and helpful?

The escaping function works with any data. If it does not work I would
get error and see why it does not work, but data would not be affected
as if things have to be escaped before entering the database those
things cannot be entered into the database unescaped.

Jean




^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Interacting with PostgreSQL
  2020-11-22 21:33 ` Marcin Borkowski
  2020-11-24 20:42   ` Tim Landscheidt
@ 2020-11-27  2:01   ` Jean Louis
  1 sibling, 0 replies; 13+ messages in thread
From: Jean Louis @ 2020-11-27  2:01 UTC (permalink / raw)
  To: Marcin Borkowski; +Cc: help-gnu-emacs, Tim Landscheidt

* Marcin Borkowski <mbork@mbork.pl> [2020-11-23 00:34]:
> Hi there,
> 
> not sure if this will help, but I sometimes use Org-mode to interact
> with Postgres:
> http://mbork.pl/2020-03-09_Using_Org-mode_as_a_PostgreSQL_client

Databases are so useful for Org mode reporting in form of tables. That
way data remains stable and centralized and can be reused dynamically
in Org files.




^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Interacting with PostgreSQL
  2020-11-27  1:40             ` Jean Louis
@ 2020-11-30  3:12               ` Tim Landscheidt
  2020-11-30  9:12                 ` Jean Louis
  0 siblings, 1 reply; 13+ messages in thread
From: Tim Landscheidt @ 2020-11-30  3:12 UTC (permalink / raw)
  To: help-gnu-emacs

Jean Louis <bugs@gnu.support> wrote:

>> >> The problem is that you do not need to consciously use auto-
>> >> commit mode, but that psql automatically reverts to it when
>> >> you rollback or commit a transaction:

>> >> | tim=> BEGIN WORK;
>> >> | BEGIN
>> >> | tim=> INSERT INTO t (ID) VALUES (1);
>> >> | INSERT 0 1
>> >> | tim=> ROLLBACK WORK;
>> >> | ROLLBACK
>> >> | tim=> INSERT INTO t (ID) VALUES (1);
>> >> | INSERT 0 1
>> >> | tim=> -- The row has been committed.

>> > I understand. I always used it manually and will rather continue. Just
>> > observing how you do it.

>> Eh, that /is/ the behaviour using it manually, either on the
>> command line or via sql-postgres.

> I understand what you mean. Without BEGIN I am in autocommit
> mode. That is standard. But why is it problem for you?

Because if I make a mistake in auto-commit mode, potentially
all data can be changed or lost.  Therefore I want to use a
transaction wherever possible so that I can verify the ef-
fects of a query before committing it.

> […]

>> There are org-mode, many markdown variants, plain HTML, and
>> apparently even a dedicated GNU project called Hyperbole
>> (https://www.gnu.org/software/hyperbole/).

> Definitely yes. But those you mentioned are related only by
> having hyperlink features. Org mode is outline mode, markdown is not
> quite outline neither hierarchical, it is pre-processor for HTML. GNU
> Hyperbole I am using daily and started using it back in time, maybe 2
> decades with pauses and never fully used all of the options it
> has. Maybe you mean Koutliner in GNU Hyperbole as that is outline
> somewhat similar to Org but better structured.

> Emacs HyperScope is dynamic knowledge repository that augments
> knowledge, relates it together and serves as dynamic knowledge
> repository that follows the technology template project for open
> hyperdocument systems by Doug Engelbart, definitely similar in its
> nature to first Javascript based HyperScope. This one is for Emacs.

> About Dynamic Knowledge Repositories (DKR)
> https://www.dougengelbart.org/content/view/190/163/

> TECHNOLOGY TEMPLATE PROJECT OHS Framework
> https://www.dougengelbart.org/content/view/110/460/

I know.  So why use that and not Org mode?

>> There are a my- riad of version control systems, with Git at the
>> forefront.  Most of them are natively supported by Emacs, right out
>> of the box.

> That is right. And I need to think about such. For example I would
> need to check in, check out, and I do that for the files.

> When editing database entries, those are not files on file
> system. Data comes from the database. That data is itself stored in
> some files that PostgreSQL database manages is irrelevant as user has
> no access to source files normally, neither is allowed to do some
> versioning with such. Interaction goes over TCP or sockets and not
> from file access. In that sense when I am editing for example Org
> based data it is not file from file system but Org mode formatted data
> then there is currently none known versioning system that I know that
> is generic for databases.

> This can be easily helped with simple procedure that function that is
> about to edit the data simply fetch the edited data and stores it in
> the version control table before any editing. Version control table
> remembers the table, column ID, column, type and value. Right now I am
> storing those as text, but not numbers as it need some type casting to
> text that I can implement later. Major problem is with larger text
> that requires sometimes longer editing.

> Because such editing is without files I would like to know if I could
> temporarily assign a disconnected file to buffer so that file get
> saved from buffer, but when I finish recursive editing that
> buffer-string gets returned to my function that stores it into
> database. That is yet unsolved problem and could be solution to safety
> of data being edited longer time.

> Two safety problems are with PostgreSQL data entry editing, one is to
> save the previouse entries or historical and that I have solved in
> very simple manner. Other problem is to solve the currently edited
> text that is nowhere saved. For that reason I wish to find way to
> automatically save the buffers somewhere but not that buffer is
> connected to the file being saved.

> Does anybody have pointers how to do that?

> […]

I have absolutely no idea /why/ someone would store Org mode
data in a database and then wonder how to implement a form
of version control for it.  Emacs is very good at editing
files, Git is very good at versioning them, it has plenty of
commands to create branches and worktrees and everything
else one of the millions of projects using it has ever need-
ed, and Emacs Lisp is more than versatile enough to code
every imaginable workflow.

Some of the brightest minds have worked on them extensively,
either from a formally educated perspective or with the ex-
perience of blood and tears.  These giants are inviting
everybody to stand on their shoulders, and neither would I
ignore them nor would I recommend others to do so.

Tim




^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Interacting with PostgreSQL
  2020-11-30  3:12               ` Tim Landscheidt
@ 2020-11-30  9:12                 ` Jean Louis
  0 siblings, 0 replies; 13+ messages in thread
From: Jean Louis @ 2020-11-30  9:12 UTC (permalink / raw)
  To: Tim Landscheidt; +Cc: help-gnu-emacs

* Tim Landscheidt <tim@tim-landscheidt.de> [2020-11-30 06:18]:
> Jean Louis <bugs@gnu.support> wrote:
> 
> >> >> The problem is that you do not need to consciously use auto-
> >> >> commit mode, but that psql automatically reverts to it when
> >> >> you rollback or commit a transaction:
> 
> >> >> | tim=> BEGIN WORK;
> >> >> | BEGIN
> >> >> | tim=> INSERT INTO t (ID) VALUES (1);
> >> >> | INSERT 0 1
> >> >> | tim=> ROLLBACK WORK;
> >> >> | ROLLBACK
> >> >> | tim=> INSERT INTO t (ID) VALUES (1);
> >> >> | INSERT 0 1
> >> >> | tim=> -- The row has been committed.
> 
> >> > I understand. I always used it manually and will rather continue. Just
> >> > observing how you do it.
> 
> >> Eh, that /is/ the behaviour using it manually, either on the
> >> command line or via sql-postgres.
> 
> > I understand what you mean. Without BEGIN I am in autocommit
> > mode. That is standard. But why is it problem for you?
> 
> Because if I make a mistake in auto-commit mode, potentially
> all data can be changed or lost.  Therefore I want to use a
> transaction wherever possible so that I can verify the ef-
> fects of a query before committing it.

That is very understandable. And I guess PostgreSQL users will use
BEGIN; and COMMIT; at all sensitive transactions.

My side here there are cases where BEGIN; COMMIT; are not needed and
this may be due to my work flow:

- all SQL is prepared in the file.

- I invoke SQL that has been written in the file, not one written with
  psql command line tool on command line, which I use for other
  purposes

- I am normally creating tables, views and triggers

- If something is wrong with table, it is not created

- If table is created but I forgot proper column name, I can still
  correct it with alter

- If anything major is wrong with table or view, it is new at creation
  time, so I do not mind and I can as well DROP TABLE and start over
  again

- Once satisfied table is working for years, sometimes it gets new
  columns

Within `psql' on command line I am normally inspecting table and
sometimes entering some values. My workflow differs.

When working within buffer with Emacs Lisp, I have something like:

(rcd-sql-begin)
(rcd-sql-do-some-deletion)

and after I am verifying the tables and when satisifed:

(rcd-sql-commit)

Working within Emacs Lisp buffer with SQL is somehow better as I can
work on database while program is being executed. I can revert with
(rcd-sql-commit) stuff related to local buffer.

> > Emacs HyperScope is dynamic knowledge repository that augments
> > knowledge, relates it together and serves as dynamic knowledge
> > repository that follows the technology template project for open
> > hyperdocument systems by Doug Engelbart, definitely similar in its
> > nature to first Javascript based HyperScope. This one is for Emacs.
> 
> > About Dynamic Knowledge Repositories (DKR)
> > https://www.dougengelbart.org/content/view/190/163/
> 
> > TECHNOLOGY TEMPLATE PROJECT OHS Framework
> > https://www.dougengelbart.org/content/view/110/460/
> 
> I know.  So why use that and not Org mode?

One good example is that Org files were meant to be plain text but
today they are not any more, they are text with a lot of structured
information and Org Emacs Lisp programs try to solve the problem by
parsing text.

https://www.dougengelbart.org/content/view/110/460/#2a1a

,----
| Elementary Objects
| 
| Objects are basic content packets of an arbitrary, user and developer
| extensible nature. Types of elementary objects could contain text,
| graphics, equations, tables, spreadsheets, canned-images, video,
| sound, code elements, etc.
`----

I am editing hyperdocuments on a meta level that then later may become
Org documents. Org allows me to insert let us say image, but there is
harder work and more effort to assign that image specific hyperlink.

Org type of a node is normally heading and such have its ambiguous
identifier such as heading name and then it requires users to decide
to make it non-ambiguous by providing either the Org ID or CUSTOM_ID
or some other identifier. In the end I have 50 duplicates minimum on
my system as headings need to be copied and the built-in copy function
C-c C-x M-w does not have and clue what is unique ID, or Org ID or
CUSTOM_ID in other words does not grant any of them their true meaning
and copies the ID even though it is specialized Org based function and
not just Emacs kill.

With few Org files it is manageable, with growing complexity of data
is becomes time wasting machine.

When using Org I can have elementary objects as heading, but in vague
manner. If I change the heading but do not have unique ID it becomes
something else, the reference to heading is lost and hyperlink may not
work. If I use some hyperlink to unique ID, then duplicates are
disturbing.

Org file does not have headings or paragraphs or list items as
elementary objects.

Example of elementary object is this hyperlink below that gives
reference to specific paragraph 2a1a:

https://www.dougengelbart.org/content/view/110/460/#2a1a

Database backed object may have by decision its unique ID about which
user never need to think later and there are no duplicates for
decades. As PostgreSQL user you know what I mean.

- Org file may include graphics but again graphics object is not
  uniquely identified and user has to think of it.

  If I wish to include graphics object I can, and it is uniquely
  identified even if I rename it or displace it, or put somewhere else
  in hierarchy or make symlink to graphics object, it remains there
  for ever for referencing

Same for graphics, equations, tables, spreadsheets, canned-images,
video, sound, code elements, etc.

In a hyperdocument I can put Gnumeric spreadsheet. In Org file I can
only hyperlink to external Gnumeric spreadsheet or use the built-in
Org table features.

Hyperdocument creation does not let user think about it, it should be
maybe one key press to create hyperdocument.

Org mode assumes that users are there to collect their pieces of
hyperlinks and hyperdocuments together. That degrades sharing
capability. 

https://www.dougengelbart.org/content/view/110/460/#2a1a

,----
|  Mixed-Object Documents
|  
|  Documents are a coherent entity made up of an arbitrary mix of
|  elementary objects bundled within a common "envelope" to be stored,
|  transmitted, read, printed, or otherwise be operated on. 2a1b1
| 
|  the MIME specification is an example of a document definition based
|  on a higher level collection of elementary objects.  2a1b2
`----

When elementary objects have been defined then a mixed-object document
can be defined. It may consist of anything. Libreoffice Spreadsheets
and spreadsheets in general, then also ODT files and packages such as
TAR, or email files may be similar to mixed-object document. Yet they
need not offer clear overview of what is inside and no meanings or
relations connecting the dots.

Org file is not mixed-object document, it is rather in itself
elementary object.

Imagine collection of PDF files, and there are 10000 references to
specific articles in PDF files tagged with specific human objects such
as cup, flower, silk and similar. Finding set of articles relating to
flower becomes tedious task. It is useful in creation of art. As that
is exactly how I have found need to create Hyperscope as dynamic
knowledge repository.

The joy of having quick access to PDF specific articles that may be
just 1/3 large on a page is great. No time spending.

One good benefit streamlines quicker location of any node or
elementary object and speed of access to such elementary object.

Enter object once. Never again construct Org hyperlinks by hand. That
principle is used by some features of Org mode but is not well
integrated yet. So people construct hyperlinks by tedious {C-c C-l}
repetition and that is not scalable.

Let us say I wish to insert collection of references, notes, tasks,
images. I can then insert such into Org file without thinking on each
of them, without constructing hyperlinks by hand or doing tedious copy
and paste. General benefit for me is speed and ease.

https://www.dougengelbart.org/content/view/110/460/#2a1c

,----
|     Shared Objects
| 
| Objects and the documents made out of them are shareable among members
| of a networked community: they may be simultaneously viewable,
| manipulable, and changeable according to rules appropriate to their
| nature and supported in access permissions and restrictions contained
| in their definitions.  2a1c1
`----

We all share hyperlinks and documents. But how do I share specific
hyperlink from Org file to specific person or group?

- Copy hyperlink
- Open chat, insert hyperlink
- maybe write description

or

- Copy hyperlink 
- Open up mail client
- Insert hyperlink
- Describe hyperlink
- Insert email address
- maybe designate my own email address

How about:

- choose person to receive this hyperlink
- press ENTER

What about hyperdocuments related to groups and people who should know
about them:

Maybe task have been assigned to group of 3 people. Am I to repeat the
actions of opening files, locating tasks for people, copying task,
opening email client, inserting task, finding email address for person
1, sending email, opening new email, yanking text inside again,
finding email address for person 2, sending email, opening new email,
yanking text, finding email for person 3, sending email.

Then I have 365 such tasks assigned to people, so let me rather kick
the wall with my head.

> Objects and the documents made out of them are shareable among members
> of a networked community: they may be simultaneously viewable

Staff member may use Emacs, but also other interface such as web
browser, or email to access document, receive it, or maybe edit on the
fly by using tramp access.

| manipulable, and changeable according to rules appropriate to their
| nature and supported in access permissions and restrictions contained
| in their definitions.

Fine access permissions and restrictions may be solved with
PostgreSQL.

Row Security Policies
https://www.postgresql.org/docs/13/ddl-rowsecurity.html

My projects are well written in logical order and consists of
strategic plan, tactical plans and multiple plans where some steps of
plans are broken down into projects and each project could be broken
down into specific atomic tasks easily doable or executable by
literate person without higher education.

One set of those tasks in a project may not be for the eyes of people
also participating in the same project. One group of people gets to do
specific tasks, other group of people do other tasks all related to
one project but not all people have permission to get insights into
security concerns. That is all easily solved on project planning with
such attributes such as access permissions and restrictions.

Defining a security policy matter of minutes and later defining group
access or individual access will give permissions accordingly.

https://www.dougengelbart.org/content/view/110/460/#2a1d

,----
|     Object ID-Time Stamps
| 
| Each creation or modification of an object automatically results in
| the creation of a stamp containing information concerning the date,
| time, date, and user identification associated with that modification.
| 2a1d1
| 
| Users can filter and control the portrayal of this information and
| their associated content objects.
`----

Org file has its objects which is handling internally such as
headings, properties, tags, body of a heading. But it is not multi
user environment. It does not have feature to have multiple users to
edit tasks, assign tasks in the same time, report on tasks with
concurrency support, where we may all know WHO edited the task and
WHEN and WHAT was previous version of task.

> > Two safety problems are with PostgreSQL data entry editing, one is to
> > save the previouse entries or historical and that I have solved in
> > very simple manner. Other problem is to solve the currently edited
> > text that is nowhere saved. For that reason I wish to find way to
> > automatically save the buffers somewhere but not that buffer is
> > connected to the file being saved.
> 
> > Does anybody have pointers how to do that?

I still need to find way how to open up buffer, edit string from
database so that the intermediate buffer editing still gets its
automatic saving but that buffer is not really connected to
file.

Maybe I could run of the timer a function in the buffer that is saving
it appropriately even inserting into database the temporary
version. So I guess that may be the simplest solution for that case.

> I have absolutely no idea /why/ someone would store Org mode
> data in a database

Org file and parts of Org files are elementary objects. Maybe because
they are part of one overall hyperdocument as mixed-object. Org file
could be one object, text other, video other object, tasks different
objects, specific paragraphs different, specific parts of Org file
different as by their access permissions. Mixed object may contain
directory subtree with bunch of files belonging to such. Including
bunch of files in Org is not integrated or available feature.

Org does not offer finely grained referencing. For example I cannot
specifically reference to report list under some heading unless I
place <<target>> but then again <<targe>> will work only for
HTML. With finely grained based elementary objects I can reference
such objects from other text parts, objects, files, including Org
files.

Today I was sending again the local village miner daily report to a
supervisor of village miners. When I was using org file the key
sequence would be about 100 chars including spaces, find the file if
not bound in bookmark or register, find specific heading, export
heading to ASCII, copy ASCII, open email, insert into email, send
email.

How about: press key to send it by email, choose person, ENTER and
email is sent.

Trying to do everything with Org is limiting my work and I have to
adapt way too many things. Then it is better working on a meta level
and creating useful functions that will relate to Org but not be
dependant of Org stuff and lack of structure.

> Emacs is very good at editing files, Git is very good at versioning
> them, it has plenty of commands to create branches and worktrees and
> everything else one of the millions of projects using it has ever
> need- ed, and Emacs Lisp is more than versatile enough to code every
> imaginable workflow.

One could say that for any mean of communication but general
availability of a tool does not make it proper for every use
case. People have been collaborating before computers as well and
before Git as well. Tools helps us to streamline our workflows, to
minimize our work and efforts, to lessen those repetitive small tasks.

Let us mention Emacs version control and Git version control. Those
are great tools definitely. But that is not everything there is as we
may indefinitely enhance our human processes. What version control
does is great.

But when looking better into it, one can see that version control
could be as well automatic. Programming RCS simpler and well working
revision control system took some time and effort to do it.

But then creating PostgreSQL table and few triggers to provide version
control for editing of any other table takes much less effort.

Then again, what if version control is simply built into file system?
Would not that alone be better?

Look here:

HAMMER is a file system written for DragonFlyBSD
https://www.dragonflybsd.org/hammer/

A convenient undo command is provided for single-file history, diffs,
and extractions. Snapshots may be used to access entire directory
trees.

That may not be "version control" as it does not solve problems that
Git is solving. But something similar could as well solving the
problems for a user transparently without users ever thinking about
version control commands, tools, how it works.

While Git has solved many problems it also created many problems due
to its complex nature. Just look on Internet how many questions are
there related to Git.

Anyway, solving rudimentary version control with PostgreSQL was few
minutes of work. I have made a table where column values from other
tables will be saved and inserted, and before editing those values,
save them in the table.

(defun hlink-edit-description (id) ;; 
  (let* ((description (hlink-description-value id)) ;; fetch description from the hyperdocument ID
	 (description (if description description "")) 
	 (buffer-name (format "HyperScope Editing ID: %d" id)) ;; prepare buffer name
	 (new-description (read-from-buffer description buffer-name))) ;; edit description
    (hyperscope-vc "hlinks" "hlinks_description" id) ;; fetch previous description and store it in version control
    (rcd-db-update-entry "hlinks" "hlinks_description" "text" id new-description *hs*))) ;; insert new description

Simple.

Triggers can be added to each database to store the whole column
values BEFORE UPDATE OR INSERT in a version control table. See:
https://www.postgresql.org/docs/13/sql-createtrigger.html

My version control for database entries relate to ANY tables and any
columns that I specifically decide to keep their revisions in the
version table. Version table is centralized.

And yet version control table could be as well automatically
constructed for each table so not to be centralized and to be
specifically related to the table for which one need version
control. Integration can be automatic:

1. Invoke function
2. Choose table A
3. Automatically construct version control table for table A
4. Automatically add triggers

Finished there. After that, no more thinking about version control for
decades. No programming, developing, files, etc. It does not solve
same problems as Git solves it but it gives oppportunity to diff
versions and see what was changed and when in a simple manner and to
request back some specific changes or whole versions from past.

When editing hyperdocuments or editing database entries, one cannot be
satisfied with Git as Git is not made for that case. Hyperdocument may
have a whole bunch of files included, let us say 50 PDF documents, and
they are not really edited rather stored and annotated in a
database. There are user permissions to be changed, so Git is not
finding itself in that sector. It does not have structured version
control, it is file system based control.

When I say structured version control I mean columns in PostgreSQL
database. If I change author's name that column has its identifier
such as hlinks_authorname and Git does not keep identifiers for finely
grained objects. It keeps it for files and finds what modifications
have been made. But I cannot search those modifications like "Tell me
who changed author's name during February 2020". It is more general
system for file versioning, not specific system for structured
objects.

Anyway it is trivial to solve the problem in a database itself so that
user need not think about that ever again. There is not even a need to
checkout, or invoke commands. PostgreSQL handles also replication, so
once connection is configured there is no need to think how it will be
replicated on other servers.

> Some of the brightest minds have worked on them extensively, either
> from a formally educated perspective or with the ex- perience of
> blood and tears.  These giants are inviting everybody to stand on
> their shoulders, and neither would I ignore them nor would I
> recommend others to do so.

Does that mean authority and well known giant minds should influence
programmers not to program but rather trust giant minds to know it
better and only follow their principles or tools or ways and methods of work?

If that is so, let us define well a list of giant minds, and let us
stop enhancing and programming forever.

Those principles would lead to nowhere. Would there be no rudimentary
version control systems, there would be no Git. Git did not come out
of nothing. Would there be no BSD or Unix system, probably would not
be there Minix and without Minix and GNU there would be no Linux
kernel as of today. Collaborating and contributing to each other is
what develops civilization. We cannot stay in place thinking that
everything one needs is already there produced by some giant minds.

And how much effort somebody put into some feature can be great and
awarding for that person and people dependable on that feature.

But it can also be nonsense and of little value for somebody else who
simply thinks different and can find ways in streamlining processes.

Let us say Org mode versus SMOS that I recently found:

SMOS - A Comprehensive Self-Management System by Tom Sydney Kerckhove
https://smos.cs-syd.eu/features

He could recognize that Org mode is not a plaint text and it is
history. Org file is free structure in the eyes of a user that Org
programs try to manage and structure to be useful for users. The
approach to manage in structural way something that was not meant to
be structured leads to complexities.

As an Org mode user he has created SMOS to streamline task
management. This makes repetition redundant and provides more
reliability. Files maybe exported as Yaml and still imported into
normal Org files (trivial to do). No wonder he has logo eating Org
mode in a sandwich. https://github.com/NorfairKing/smos

SMOS have been built as inspired by Org task management. Org have been
built as expired by Outline mode and plethora of other references.

I could say why Org mode was not built on a database backend? Because
author started in plain text. Would database like GDBM or similar
already be included in Emacs maybe it would have until today many
database backed features. Emacs does everything possible to keep
things in a database.

init file is sample of a database that lacks concurrency
support. Users are allowed to edit various variables and configure
them and they are colliding with the custom system or
custom-set-variables.

Old and new users need to cope with same problem of lack of
concurrency since decades.

My database approach to configuration would be simple:

- variable
- value
- boolean toggle if variable is locked or not.

Locked variable would not get overwritten by other variable,
defcustom, you name it. Once user makes decision this would not get
overwritten by anything. Finally init.el or .emacs file belongs to
user, and not to programmer and user should have full control over it.

Jean




^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2020-11-30  9:12 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-11-21 23:51 Interacting with PostgreSQL Tim Landscheidt
2020-11-22  1:33 ` Jean Louis
2020-11-24 23:14   ` Tim Landscheidt
2020-11-25  4:18     ` Jean Louis
2020-11-25 10:37       ` Tim Landscheidt
2020-11-25 14:25         ` Jean Louis
2020-11-25 17:08           ` Tim Landscheidt
2020-11-27  1:40             ` Jean Louis
2020-11-30  3:12               ` Tim Landscheidt
2020-11-30  9:12                 ` Jean Louis
2020-11-22 21:33 ` Marcin Borkowski
2020-11-24 20:42   ` Tim Landscheidt
2020-11-27  2:01   ` Jean Louis

Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.