From 2bba7ea620cc6c257238d250690dc903d28ade95 Mon Sep 17 00:00:00 2001 From: Sabra Crolleton Date: Wed, 8 Jul 2020 16:48:16 -0400 Subject: [PATCH 1/3] Add additional method for dynamic queries to docs It is possible to use variables in s-sql select statements if the variable is passing symbols. Consider the following two toy examples. (let ((table 'quotations) (col1 'id) (col2 'text)) (with-connection (list "personal_stuff" "sabra" "mypassword" "localhost") (query (:fetch (:select col1 col2 :from table) 1 6)))) ((543 "I may have settled in shipping.")) (let ((table :quotations) (col1 :id) (col2 :text)) (with-connection (list "personal_stuff" "sabra" "mypassword" "localhost") (query (:fetch (:select col1 col2 :from table) 1 6)))) ((543 "I may have settled in shipping.")) --- doc/s-sql.html | 631 ++++++++++++++++++++++++++----------------------- doc/s-sql.org | 38 ++- 2 files changed, 365 insertions(+), 304 deletions(-) diff --git a/doc/s-sql.html b/doc/s-sql.html index 849925e..6cc9ee1 100644 --- a/doc/s-sql.html +++ b/doc/s-sql.html @@ -1,7 +1,7 @@ - + S-SQL Reference Manual @@ -447,12 +447,12 @@

Table of Contents

is all that is needed to produce the final SQL query.

-
-

Interface

+
+

Interface

-
-

macro sql (form)

+
+

macro sql (form)

→ string @@ -483,8 +483,8 @@

-

function sql-compile (form)

+
+

function sql-compile (form)

→ string @@ -516,8 +516,8 @@

-

function sql-template (form)

+
+

function sql-template (form)

In cases where you do need to build the query at run time, yet you do not @@ -530,8 +530,8 @@

-

function enable-s-sql-syntax (&optional (char #\Q))

+
+

function enable-s-sql-syntax (&optional (char #\Q))

Modifies the current readtable to add a #Q syntax that is read as (sql …). @@ -539,8 +539,8 @@

-

function sql-escape-string (string)

+
+

function sql-escape-string (string)

→ string @@ -559,8 +559,8 @@

-

method sql-escape (value)

+
+

method sql-escape (value)

→ string @@ -586,16 +586,16 @@

-

variable downcase-symbols

+
+

variable downcase-symbols

When converting symbols to strings, whether to downcase the symbols is set here. The default is to downcase symbols.

-
-

variable standard-sql-strings

+
+

variable standard-sql-strings

Used to configure whether S-SQL will use standard SQL strings (just replace #\' with ''), or backslash-style escaping. Setting this to NIL is always safe, but when the server is configured to allow standard strings (compile-time parameter 'standard_conforming_strings' is 'on', which will become the default in future versions of PostgreSQL), the noise in queries can be reduced by setting this to T. @@ -603,8 +603,8 @@

-

variable postgres-reserved-words hashtable

+
+

variable postgres-reserved-words hashtable

A set of all Postgresql's reserved words, for automatic escaping. Probably not a good idea to use these words as identifiers anyway. @@ -623,8 +623,8 @@

-

variable escape-sql-names-p

+
+

variable escape-sql-names-p

Determines whether double quotes are added around column, table, and ** function names in @@ -651,8 +651,8 @@

-

function sql-type-name (type)

+
+

function sql-type-name (type)

→ string @@ -664,8 +664,8 @@

-

function to-sql-name (name &optional (escape-p escape-sql-names-p)(ignore-reserved-words nil)

+
+

function to-sql-name (name &optional (escape-p escape-sql-names-p)(ignore-reserved-words nil)

→ string @@ -681,8 +681,8 @@

-

function from-sql-name (string)

+
+

function from-sql-name (string)

→ keyword @@ -695,8 +695,8 @@

-

macro register-sql-operators (arity &rest names)

+
+

macro register-sql-operators (arity &rest names)

Define simple SQL operators. Arity is one of :unary (like 'not'), :unary-postfix @@ -710,8 +710,8 @@

-

SQL Types

+
+

SQL Types

S-SQL knows the SQL equivalents to a number of Lisp types, and defines some @@ -831,8 +831,8 @@

-

type db-null

+
+

type db-null

This is a type of which only the keyword :null is a member. It is used to represent @@ -842,8 +842,8 @@

-

SQL Syntax

+
+

SQL Syntax

An S-SQL form is converted to a query through the following rules: @@ -864,8 +864,8 @@

-

sql-op :select (&rest args)

+
+

sql-op :select (&rest args)

Creates a select query. The arguments are split on the keywords found among @@ -912,12 +912,12 @@

-

Joins

+
+

Joins

-
-

Cross Join

+
+

Cross Join

From the postgresql documentation: "For every possible combination of rows from T1 and T2 (i.e., a Cartesian product), the joined table will contain a row consisting of all columns in T1 followed by all columns in T2. If the tables have N and M rows respectively, the joined table will have N * M rows." @@ -929,8 +929,8 @@

Cross Join<

-
-

Inner Join

+
+

Inner Join

An inner join looks at two tables and creates a new result consisting of the selected elements in the rows from the two tables that match the specified conditions. You can simplistically think of it as the intersection of the two sets. In reality, it is creating a new set consisting of certain elements of the intersecting rows. An inner join is the default and need not be specified. @@ -999,8 +999,8 @@

Inner Join<

-
-

Outer Join

+
+

Outer Join

An outer join not only generates an inner join, it also joins the rows from one table that matches the conditions and adds null values for the joined columns from the second table (which obviously did not match the condition.) Under Postgresql, a "left join", "right join" or "full join" all imply an outer join. @@ -1012,8 +1012,8 @@

Outer Join<

-
-

Left Join

+
+

Left Join

Example: Here we assume two tables. A countries table and a many-to-many linking table named countries-topics. (There is an implicit third table named topics.) We are looking for records from the countries table which do not have a match in the countries-topics table. In other words, where do we have a note, but not matched it to a topic? @@ -1048,16 +1048,16 @@

Left Join

-
-

Defined Operators

+
+

Defined Operators

The following operators are defined:

-
-

sql-op :+, :*, :%, :&, :|, :||, :and, :or, :=, :/, :!=, :<, :>, :<=, :>=, :^, :union, :union-all, :intersect, :intersect-all, :except, :except-all (&rest args)

+
+

sql-op :+, :*, :%, :&, :|, :||, :and, :or, :=, :/, :!=, :<, :>, :<=, :>=, :^, :union, :union-all, :intersect, :intersect-all, :except, :except-all (&rest args)

These are expanded as infix operators. When meaningful, they allow more than @@ -1073,8 +1073,8 @@

-

sql-op :or

+
+

sql-op :or

(query (:select 'countries.name
@@ -1100,8 +1100,8 @@ 

sql-op :or<

-
-

sql-op :intersect

+
+

sql-op :intersect

Intersect produces a result contain rows that appear on all the sub-selects. @@ -1118,8 +1118,8 @@

sql-op :int

-
-

sql-op :union, :union-all

+
+

sql-op :union, :union-all

The union operation generally eliminates what it thinks are duplicate rows. The union-all operation preserves duplicate rows. The examples below use the union-all operator, but the syntax would be the same with union. @@ -1154,8 +1154,8 @@

sql-op :uni

-
-

sql-op :except, :except-all

+
+

sql-op :except, :except-all

:except removes all matches. :except-all is slightly different. @@ -1177,8 +1177,8 @@

sql-op :exc

-
-

sql-op :~, :not (arg)

+
+

sql-op :~, :not (arg)

Unary operators for bitwise and logical negation. @@ -1194,8 +1194,8 @@

-

sql-op :any, :any*

+
+

sql-op :any, :any*

Any needs to be considered as a special case. Quoting Marijn Haverbeke here,"Postgres has both a function-call-style any and an infix any, and S-SQL's syntax doesn't allow them to be distinguished." As a result, postmodern has a regular :any sql-op and a :any* sql-op, which expand slightly differently. @@ -1303,8 +1303,8 @@

sql-op :any

-
-

sql-op :function (name (&rest arg-types) return-type stability body)

+
+

sql-op :function (name (&rest arg-types) return-type stability body)

Create a stored procedure. The argument and return types are interpreted as @@ -1319,8 +1319,8 @@

-

sql-op :~, :~*, :!~, :!~* (string pattern)

+
+

sql-op :~, :~*, :!~, :!~* (string pattern)

Regular expression matching operators. The exclamation mark means 'does not match', @@ -1366,8 +1366,8 @@

-

sql-op :like, :ilike (string pattern)

+
+

sql-op :like, :ilike (string pattern)

Simple SQL string matching operators (:ilike is case-insensitive). @@ -1380,8 +1380,8 @@

-

sql-op :@@

+
+

sql-op :@@

Fast Text Search match operator. @@ -1389,8 +1389,8 @@

-

sql-op :desc (column)

+
+

sql-op :desc (column)

Used to invert the meaning of an operator in an :order-by clause. @@ -1405,8 +1405,8 @@

-

sql-op :nulls-first, :nulls-last (column)

+
+

sql-op :nulls-first, :nulls-last (column)

Used to determine where :null values appear in an :order-by clause. @@ -1414,8 +1414,8 @@

-

sql-op :as (form name &rest fields)

+
+

sql-op :as (form name &rest fields)

Also known in some explanations as "alias". This assigns a name to a column or @@ -1470,8 +1470,8 @@

-

sql-op :cast (query)

+
+

sql-op :cast (query)

The CAST operator. Takes a query as an argument, and returns the result @@ -1500,8 +1500,8 @@

-

sql-op :type (query)

+
+

sql-op :type (query)

Is similar to cast but uses the postgresql :: formating. Unlike cast it will not @@ -1519,8 +1519,8 @@

-

sql-op :create-composite-type (type-name &rest args)

+
+

sql-op :create-composite-type (type-name &rest args)

Creates a composite type with a type-name and two or more columns. E.g. @@ -1531,8 +1531,8 @@

-

sql-op :exists (query)

+
+

sql-op :exists (query)

The EXISTS operator. Takes a query as an argument, and returns true or false @@ -1552,8 +1552,8 @@

-

sql-op :is-null (arg)

+
+

sql-op :is-null (arg)

Test whether a value is null. @@ -1564,8 +1564,8 @@

-

sql-op :not-null (arg)

+
+

sql-op :not-null (arg)

Test whether a value is not null. @@ -1576,8 +1576,8 @@

-

sql-op :in (value set)

+
+

sql-op :in (value set)

Test whether a value is in a set of values. @@ -1597,8 +1597,8 @@

-

sql-op :not-in (value set)

+
+

sql-op :not-in (value set)

Inverse of the above. @@ -1606,8 +1606,8 @@

-

sql-op :set (&rest elements)

+
+

sql-op :set (&rest elements)

Denote a set of values. This operator has two interfaces. When @@ -1682,8 +1682,8 @@

-

sql-op :array (query)

+
+

sql-op :array (query)

This is used when calling a select query into an array. See array-notes.html @@ -1708,8 +1708,8 @@

-

sql-op :array[] (&rest args)

+
+

sql-op :array[] (&rest args)

This is the general operator for arrays. It also handles statements that include @@ -1730,8 +1730,8 @@

-

sql-op :[] (form start &optional end)

+
+

sql-op :[] (form start &optional end)

Dereference an array value. If end is provided, extract a slice of the array. @@ -1747,8 +1747,8 @@

-

sql-op :extract (unit form)

+
+

sql-op :extract (unit form)

Extract a field from a date/time value. For example, (:extract :month (:now)). @@ -1767,8 +1767,8 @@

-

sql-op :case (&rest clauses)

+
+

sql-op :case (&rest clauses)

A conditional expression. Clauses should take the form (test value). If @@ -1783,8 +1783,8 @@

-

sql-op :between (n start end)

+
+

sql-op :between (n start end)

Test whether a value lies between two other values. @@ -1798,8 +1798,8 @@

-

sql-op :between-symmetric (n start end)

+
+

sql-op :between-symmetric (n start end)

Works like :between, except that the start value is not required to be @@ -1808,8 +1808,8 @@

-

sql-op :dot (&rest names)

+
+

sql-op :dot (&rest names)

Can be used to combine multiple names into a name of the form A.B to @@ -1819,8 +1819,8 @@

-

sql-op :type (form type)

+
+

sql-op :type (form type)

Add a type declaration to a value, as in in "4.3::real". The second @@ -1833,8 +1833,8 @@

-

sql-op :raw (string)

+
+

sql-op :raw (string)

Insert a string as-is into the query. This can be useful for doing things @@ -1851,8 +1851,8 @@

-

sql-op :fetch (form amount &optional offset)

+
+

sql-op :fetch (form amount &optional offset)

Fetch is a more efficient way to do pagination instead of using limit and @@ -1879,8 +1879,8 @@

-

sql-op :limit (query amount &optional offset)

+
+

sql-op :limit (query amount &optional offset)

In S-SQL limit is not part of the select operator, but an extra @@ -1896,8 +1896,8 @@

-

sql-op :order-by (query &rest exprs)

+
+

sql-op :order-by (query &rest exprs)

Order the results of a query by the given expressions. See :desc for @@ -1914,8 +1914,8 @@

-

sql-op :values

+
+

sql-op :values

Values computes a row value or set of row values for use in a specific @@ -1950,8 +1950,8 @@

-

sql-op :empty-set

+
+

sql-op :empty-set

This is a fudge. It returns a string "()" where something like '() @@ -1967,8 +1967,8 @@

-

sql-op :group-by

+
+

sql-op :group-by

https://www.postgresql.org/docs/current/static/queries-table-expressions.html#QUERIES-GROUPING-SETS @@ -1993,8 +1993,8 @@

-

sql-op :grouping-sets

+
+

sql-op :grouping-sets

https://www.postgresql.org/docs/current/static/queries-table-expressions.html#QUERIES-GROUPING-SETS @@ -2014,20 +2014,20 @@

-

Time, Date and Interval Operators

+
+

Time, Date and Interval Operators

-
-

sql-op :interval (arg)

+
+

sql-op :interval (arg)

Creates an interval data type, generally represented in postmodern as an alist

-
-

sql-op :current-date ()

+
+

sql-op :current-date ()

(query (:select (:current-date)) :single)
@@ -2035,33 +2035,33 @@ 

-

sql-op :current-time ()

+
+

sql-op :current-time ()

-
-

sql-op :current-timestamp ()

+
+

sql-op :current-timestamp ()

-
-

sql-op :timestamp (arg)

+
+

sql-op :timestamp (arg)

-
-

sql-op :age (&rest args)

+
+

sql-op :age (&rest args)

-
-

sql-op :date (arg)

+
+

sql-op :date (arg)

-
-

sql-op :make-interval (&rest args)

+
+

sql-op :make-interval (&rest args)

Takes lists of (time-unit value) and returns a timestamp type. Example: @@ -2074,8 +2074,8 @@

-

sql-op :make-timestamp (&rest args)

+
+

sql-op :make-timestamp (&rest args)

Takes lists of (time-unit value) and returns a timestamptz type. Example: @@ -2089,8 +2089,8 @@

-

sql-op :make-timestamptz (&rest args)

+
+

sql-op :make-timestamptz (&rest args)

Takes lists of (time-unit value) and returns a timestamptz type. Example: @@ -2106,12 +2106,12 @@

-

Aggregation Operators

+
+

Aggregation Operators

-
-

sql-op :count (&rest args)

+
+

sql-op :count (&rest args)

Count returns the number of rows for which the expression is not null. @@ -2164,8 +2164,8 @@

-

sql-op :avg (&rest rest args)

+
+

sql-op :avg (&rest rest args)

Avg calculates the average value of a list of values. Note that if the @@ -2180,8 +2180,8 @@

-

sql-op :sum (&rest rest args)

+
+

sql-op :sum (&rest rest args)

Sum calculates the total of a list of values. Note that if the keyword filter @@ -2198,8 +2198,8 @@

-

sql-op ::max (&rest args)

+
+

sql-op ::max (&rest args)

max returns the maximum value of a set of values. Note that if the filter @@ -2216,8 +2216,8 @@

-

sql-op ::min (&rest args)

+
+

sql-op ::min (&rest args)

min returns the minimum value of a set of values. Note that if the filter @@ -2234,8 +2234,8 @@

-

sql-op ::every (&rest args)

+
+

sql-op ::every (&rest args)

Every returns true if all input values are true, otherwise false. Note @@ -2253,8 +2253,8 @@

-

sql-op :percentile-cont (&rest args)

+
+

sql-op :percentile-cont (&rest args)

Requires Postgresql 9.4 or higher. Percentile-cont returns a value @@ -2278,8 +2278,8 @@

-

sql-op :percentile-dist (&rest args)

+
+

sql-op :percentile-dist (&rest args)

Requires Postgresql 9.4 or higher. There are two required keyword parameters @@ -2304,8 +2304,8 @@

-

sql-op :corr (y x)

+
+

sql-op :corr (y x)

The corr function returns the correlation coefficient between a set of @@ -2319,8 +2319,8 @@

-

sql-op :covar-pop (y x)

+
+

sql-op :covar-pop (y x)

The covar-pop function returns the population covariance between a set of @@ -2334,8 +2334,8 @@

-

sql-op :covar-samp (y x)

+
+

sql-op :covar-samp (y x)

(query (:select (:covar-samp 'height 'weight)
@@ -2349,8 +2349,8 @@ 

-

sql-op :string-agg (&rest args)

+
+

sql-op :string-agg (&rest args)

String-agg allows you to concatenate strings using different types of @@ -2375,8 +2375,8 @@

-

sql-op :array-agg (&rest args)

+
+

sql-op :array-agg (&rest args)

Array-agg returns a list of values concatenated into an arrays. @@ -2406,8 +2406,8 @@

-

sql-op :mode (&rest args)

+
+

sql-op :mode (&rest args)

Mode is used to find the most frequent input value in a group. @@ -2422,8 +2422,8 @@

-

sql-op :regr_avgx (y x)

+
+

sql-op :regr_avgx (y x)

The regr_avgx function returns the average of the independent variable @@ -2437,8 +2437,8 @@

-

sql-op :regr_avgy (y x)

+
+

sql-op :regr_avgy (y x)

The regr_avgy function returns the average of the dependent variable @@ -2454,8 +2454,8 @@

-

sql-op :regr_count (y x)

+
+

sql-op :regr_count (y x)

The regr_count function returns the number of input rows in which both @@ -2469,8 +2469,8 @@

-

sql-op :regr_intercept (y x)

+
+

sql-op :regr_intercept (y x)

The regr_intercept function returns the y-intercept of the least-squares-fit @@ -2484,8 +2484,8 @@

-

sql-op :regr_r2 (y x)

+
+

sql-op :regr_r2 (y x)

The regr_r2 function returns the square of the correlation coefficient. Example: @@ -2498,8 +2498,8 @@

-

sql-op :regr_slope (y x)

+
+

sql-op :regr_slope (y x)

The regr_slope function returns the slope of the least-squares-fit linear @@ -2513,8 +2513,8 @@

-

sql-op :regr_sxx (y x)

+
+

sql-op :regr_sxx (y x)

The regr_sxx function returns the sum(X^2) - sum(X)^2/N (“sum of squares” of @@ -2528,8 +2528,8 @@

-

sql-op :regr_sxy (y x)

+
+

sql-op :regr_sxy (y x)

The regr_sxy function returns the sum(X*Y) - sum(X) * sum(Y)/N (“sum of products” @@ -2543,8 +2543,8 @@

-

sql-op :regr_syy (y x)

+
+

sql-op :regr_syy (y x)

The regr_syy function returns the sum(Y^2) - sum(Y)^2/N (“sum of squares” @@ -2558,8 +2558,8 @@

-

sql-op :stddev (&rest args)

+
+

sql-op :stddev (&rest args)

The stddev function returns the the sample standard deviation of the input @@ -2573,8 +2573,8 @@

-

sql-op :stddev-pop (&rest args)

+
+

sql-op :stddev-pop (&rest args)

The stddev-pop function returns the population standard deviation of the @@ -2588,8 +2588,8 @@

-

sql-op :stddev-samp (&rest args)

+
+

sql-op :stddev-samp (&rest args)

The stddev-samp function returns the sample standard deviation of the @@ -2603,8 +2603,8 @@

-

sql-op :variance (&rest args)

+
+

sql-op :variance (&rest args)

Variance is a historical alias for var_samp. The variance function returns @@ -2619,8 +2619,8 @@

-

sql-op :var-pop (&rest args)

+
+

sql-op :var-pop (&rest args)

The var-pop function returns the population variance of the input values @@ -2635,8 +2635,8 @@

-

sql-op :var-samp (&rest args)

+
+

sql-op :var-samp (&rest args)

The var-samp function returns the sample variance of the input values @@ -2654,8 +2654,8 @@

-

sql-op :over (form &rest args)

+
+

sql-op :over (form &rest args)

Over, partition-by and window are so-called window functions. A window @@ -2670,8 +2670,8 @@

-

sql-op :partition-by (&rest args)

+
+

sql-op :partition-by (&rest args)

Args is a list of one or more columns to partition by, optionally @@ -2699,8 +2699,8 @@

-

sql-op :window (form)

+
+

sql-op :window (form)

(query (:select (:over (:sum 'salary) 'w)
@@ -2712,8 +2712,8 @@ 

-

sql-op :with (&rest args)

+
+

sql-op :with (&rest args)

With provides a way to write auxillary statements for use in a larger query, @@ -2736,8 +2736,8 @@

-

sql-op :with-recursive (&rest args)

+
+

sql-op :with-recursive (&rest args)

Recursive modifier to a WITH statement, allowing the query to refer to its own output. @@ -2795,12 +2795,12 @@

-

Table Functions

+
+

Table Functions

-
-

sql-op :for-update (query &key of nowait)

+
+

sql-op :for-update (query &key of nowait)

Locks the selected rows against concurrent updates. This will prevent the @@ -2819,8 +2819,8 @@

-

sql-op :for-share (query &key of nowait)

+
+

sql-op :for-share (query &key of nowait)

Similar to :for-update, except it acquires a shared lock on the table, @@ -2830,8 +2830,8 @@

-

sql-op :insert-into (table &rest rest)

+
+

sql-op :insert-into (table &rest rest)

Insert a row into a table. When the second argument is :set, the other @@ -2870,8 +2870,8 @@

-

sql-op :insert-rows-into (table &rest rest)

+
+

sql-op :insert-rows-into (table &rest rest)

Insert multiple rows into a table. Specify the columns first with the @@ -2896,8 +2896,8 @@

-

sql-op :update (table &rest rest)

+
+

sql-op :update (table &rest rest)

Update values in a table. After the table name there should follow the @@ -2911,8 +2911,8 @@

-

sql-op :delete-from (table &rest rest)

+
+

sql-op :delete-from (table &rest rest)

Delete rows from the named table. Can be given a :where argument followed @@ -2925,8 +2925,8 @@

-

sql-op :create-table (name (&rest columns) &rest options)

+
+

sql-op :create-table (name (&rest columns) &rest options)

Create a new table. The simplest example would pass two parameters, @@ -2948,8 +2948,8 @@

-

Column Definition parameters

+
+

Column Definition parameters

After the table name a list of column definitions @@ -3020,8 +3020,8 @@

-

Table Constraints

+
+

Table Constraints

After the list of columns, zero or more extra options (table constraints) can @@ -3099,8 +3099,8 @@

-

sql-op :alter-table (name action &rest args)

+
+

sql-op :alter-table (name action &rest args)

Alters named table. Currently changing a column's data type is not supported. @@ -3179,8 +3179,8 @@

-

sql-op :drop-table (name)

+
+

sql-op :drop-table (name)

Drops the named table. You may optionally pass :if-exists before the name @@ -3205,8 +3205,8 @@

-

sql-op :truncate (&rest args)

+
+

sql-op :truncate (&rest args)

Truncates one or more tables, deleting all the rows. Optional keyword arguments are @@ -3240,8 +3240,8 @@

-

sql-op :create-index (name &rest args)

+
+

sql-op :create-index (name &rest args)

Create an index on a table. After the name of the index the keyword :on should @@ -3260,8 +3260,8 @@

-

sql-op :create-unique-index (name &rest args)

+
+

sql-op :create-unique-index (name &rest args)

Works like :create-index, except that the index created is unique. @@ -3269,8 +3269,8 @@

-

sql-op :drop-index (name)

+
+

sql-op :drop-index (name)

Drop an index. Takes :if-exists and/or :cascade arguments like :drop-table. @@ -3288,8 +3288,8 @@

-

sql-op :create-sequence (name &key increment min-value max-value start cache cycle)

+
+

sql-op :create-sequence (name &key increment min-value max-value start cache cycle)

Create a sequence with the given name. The rest of the arguments control @@ -3298,8 +3298,8 @@

-

sql-op :alter-sequence (name)

+
+

sql-op :alter-sequence (name)

Alters a sequence. See Postgresql documentation for parameters. @@ -3339,8 +3339,8 @@

-

sql-op :drop-sequence (name)

+
+

sql-op :drop-sequence (name)

Drop a sequence. Takes :if-exists and/or :cascade arguments like :drop-table. @@ -3355,8 +3355,8 @@

-

sql-op :create-view (name query)

+
+

sql-op :create-view (name query)

Create a view from an S-SQL-style query. @@ -3364,8 +3364,8 @@

-

sql-op :drop-view (name)

+
+

sql-op :drop-view (name)

Drop a view. Takes optional :if-exists argument. @@ -3373,8 +3373,8 @@

-

sql-op :set-constraints (state &rest constraints)

+
+

sql-op :set-constraints (state &rest constraints)

Configure whether deferrable constraints should be checked when a statement @@ -3387,8 +3387,8 @@

-

sql-op :listen (channel)

+
+

sql-op :listen (channel)

Tell the server to listen for notification events on channel channel, @@ -3397,8 +3397,8 @@

-

sql-op :unlisten (channel)

+
+

sql-op :unlisten (channel)

Stop listening for events on channel. @@ -3406,8 +3406,8 @@

-

sql-op :notify (channel &optional payload)

+
+

sql-op :notify (channel &optional payload)

Signal a notification event on channel channel, a string. The optional @@ -3416,8 +3416,8 @@

-

sql-op :create-role (role &rest args)

+
+

sql-op :create-role (role &rest args)

Create a new role (user). Following the role name are optional keywords @@ -3494,8 +3494,8 @@

-

sql-op :create-database (name)

+
+

sql-op :create-database (name)

Create a new database with the given name. @@ -3503,8 +3503,8 @@

-

sql-op :drop-database (name)

+
+

sql-op :drop-database (name)

Drops the named database. You may optionally pass :if-exists before the @@ -3519,8 +3519,8 @@

-

sql-op :copy (table &rest args)

+
+

sql-op :copy (table &rest args)

Move data between Postgres tables and filesystem files. Table name is required @@ -3550,13 +3550,13 @@

-

Dynamic Queries, Composition and Parameterized Queries

+
+

Dynamic Queries, Composition and Parameterized Queries

-
-

Overview

+
+

Overview

The question gets asked how to build dynamic or composable queries in @@ -3566,8 +3566,8 @@

-

Programmer Built Queries

+
+

Programmer Built Queries

If you are not using s-sql, then it becomes easy. The query macro @@ -3581,8 +3581,9 @@

"Mary" 60020 "06/08/02" "Toronto" "W" 34))))

+
-
    -
  1. Approach #1 Use sql-compile
  2. -
- +
    +
  • Approach #1 Use sql-compile
    +

    Sql-compile does a run-time compilation of an s-sql expression. In the following example, we create a function that accepts a where-clause, a @@ -3775,11 +3776,11 @@

    -
  • Approach #2 Use :raw
  • - - +
  • Approach #2 Use :raw
    +

    To quote Marijn, the :raw keyword takes a string and inserts it straight into the query. I try to stay away from :raw if possible, but @@ -3791,10 +3792,40 @@

    Approach #3 Using symbols in variables
    +
    +

    +Consider the following two toy examples where we determine the table and columns +to be selected using symbols (either keyword or quoted) inside variables. +

    +
    +
    (let ((table 'quotations) (col1 'id) (col2 'text))
    +  (with-connection (list "personal_stuff" "sabra" "mypassword" "localhost")
    +    (query (:fetch (:select col1 col2 :from table) 1 6))))
    +
    +((543 "I may have settled in shipping."))
    +
    +(let ((table :quotations) (col1 :id) (col2 :text))
    +  (with-connection (list "personal_stuff" "sabra" "mypassword" "localhost")
    +    (query (:fetch (:select col1 col2 :from table) 1 6))))
     
    -
    -

    Queries with User Input

    +((543 "I may have settled in shipping.")) +
    +
    +

    +This will not work if you use strings instead of symbols because sql-expand +will wrap the strings in the variables in escape format as if they were string +constants and Postgresql will throw an error because it is not expecting +string constants in the middle of a select statement. +

    +
    +

  • +

+
+
+

Queries with User Input

In any of the above approaches to building queries you will need to diff --git a/doc/s-sql.org b/doc/s-sql.org index 3be1794..443f97b 100644 --- a/doc/s-sql.org +++ b/doc/s-sql.org @@ -2555,8 +2555,9 @@ string (query (format nil "select ~a from ~a where ~a" "carrots" "garden" "length > 3")) #+END_SRC -With s-sql, there are generally two approaches to building dynamic or -composible queries: either use sql-compile or use :raw. +With s-sql, there are generally three approaches to building dynamic or +composible queries: either use sql-compile or use :raw or you can pass +symbols as variables. For purposes of this example, we will use the following employee table: @@ -2582,7 +2583,10 @@ For purposes of this example, we will use the following employee table: (9 "Mary" 60020 "06/08/02" "Toronto" "W" 34)))) #+END_SRC -1. Approach #1 Use sql-compile +**** Approach #1 Use sql-compile + :PROPERTIES: + :CUSTOM_ID: 523172f6-bc0b-4402-aa40-989025e0d12f + :END: Sql-compile does a run-time compilation of an s-sql expression. In the following example, we create a function that accepts a where-clause, a @@ -2716,7 +2720,10 @@ postgresql server versionr: (to-sql-name table-name)))) #+END_SRC -2. Approach #2 Use :raw +**** Approach #2 Use :raw + :PROPERTIES: + :CUSTOM_ID: f0c37b97-4907-4153-bdfb-3381ae4a08d7 + :END: To quote Marijn, the :raw keyword takes a string and inserts it straight into the query. I try to stay away from :raw if possible, but @@ -2726,6 +2733,29 @@ sometimes... (query (:select (:raw "tmp1.name") :from (:as 'baz (:raw "tmp1")))) #+END_SRC +**** Approach #3 Using symbols in variables + :PROPERTIES: + :CUSTOM_ID: 13c9d0df-7b08-4788-bca9-be650e42809a + :END: +Consider the following two toy examples where we determine the table and columns +to be selected using symbols (either keyword or quoted) inside variables. +#+BEGIN_SRC lisp +(let ((table 'quotations) (col1 'id) (col2 'text)) + (with-connection (list "personal_stuff" "sabra" "mypassword" "localhost") + (query (:fetch (:select col1 col2 :from table) 1 6)))) + +((543 "I may have settled in shipping.")) + +(let ((table :quotations) (col1 :id) (col2 :text)) + (with-connection (list "personal_stuff" "sabra" "mypassword" "localhost") + (query (:fetch (:select col1 col2 :from table) 1 6)))) + +((543 "I may have settled in shipping.")) +#+END_SRC +This will not work if you use strings instead of symbols because sql-expand +will wrap the strings in the variables in escape format as if they were string +constants and Postgresql will throw an error because it is not expecting +string constants in the middle of a select statement. *** Queries with User Input :PROPERTIES: :CUSTOM_ID: queries-with-user-input From 4e5db841ef3132342c0109f2bffe0e4a474e7118 Mon Sep 17 00:00:00 2001 From: Sabra Crolleton Date: Sat, 11 Jul 2020 08:02:51 -0400 Subject: [PATCH 2/3] Added explanation comment in a test. --- s-sql/tests/tests.lisp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/s-sql/tests/tests.lisp b/s-sql/tests/tests.lisp index 8096cab..f8ad0c7 100644 --- a/s-sql/tests/tests.lisp +++ b/s-sql/tests/tests.lisp @@ -1490,7 +1490,7 @@ that the table will need to be scanned twice. Everything is a trade-off." "CREATE VIEW quagmire_hollow AS (SELECT id, name FROM employee)")) (with-test-connection (unless (table-exists-p 'employee) (build-employee-table)) - (when (view-exists-p 'quagmire) + (when (view-exists-p 'quagmire) ; this avoids a warning compared to (query (:drop-view :if-exists 'quagmire)) (query (:drop-view 'quagmire))) (query (:create-view 'quagmire (:select 'id 'name :from 'employee))) (is (member :QUAGMIRE (list-views) :test 'eq)) From 01c047ef5f4f84ed955d9d8b3f2acc34e5833ae7 Mon Sep 17 00:00:00 2001 From: Sabra Crolleton Date: Fri, 21 Aug 2020 12:08:00 -0400 Subject: [PATCH 3/3] Fix issue 247 unescaped quotes in docstring --- postmodern/util.lisp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/postmodern/util.lisp b/postmodern/util.lisp index c8dd6ff..bffe3c7 100644 --- a/postmodern/util.lisp +++ b/postmodern/util.lisp @@ -100,12 +100,12 @@ fully qualified, it will assume that the schema should be \"public\"." (split-sequence:split-sequence #\, (subseq str 1 (- (length str) 1)))) (defun postgres-array-string-to-array (str) - "Takes a postgresql array in the form of a string like -\"{wol=CTc/wol,a=c/wol,b=c/wol}\" and returns a lisp array like - #("wol=CTc/wol" "a=c/wol" "b=c/wol")" - (let* ((lst (postgres-array-string-to-list str)) - (len (length lst))) - (make-array len :initial-contents lst))) + "Takes a postgresql array in the form of a string like + \"{wol=CTc/wol,a=c/wol,b=c/wol}\" and returns a lisp array like + #(\"wol=CTc/wol\" \"a=c/wol\" \"b=c/wol\")" + (let* ((lst (postgres-array-string-to-list str)) + (len (length lst))) + (make-array len :initial-contents lst))) (defun add-comment (type name comment &optional (second-name "")) "Attempts to add a comment to a particular database object. The first