2.4.0 - 2024-05-27
NativeStatement::executePrepared()
now usespg_wrapper
'sPreparedStatement::executeParams()
under the hood, all parameter values should be passed in the$params
argument. This was already the case whenNativeStatement
was built from a statement initially containing named parameters, but not positional ones.NativeStatement::prepare()
will fetch info on parameter types from the DB if some types are not given explicitly either in$paramTypes
argument or via typecasts in the query itself. Previously these types were inferred from the types of parameter values on PHP side.- No longer use names deprecated in
pg_wrapper
2.4.0:ResultSet
->Result
,Connection::getResource()
->Connection::getNative()
.
NativeStatement::prepare()
now accepts $resultTypes
argument that will be passed on to Result
instances
returned by the created PreparedStatement
instance.
$resultTypes
argument for NativeStatement::executePrepared()
method, the types should be passed to prepare()
.
2.3.1 - 2023-11-15
- It is now possible to generate SQL suitable for
PDO::prepare()
even if a query does not contain placeholders, see issue #15. Enabled by a new$forcePDOPrepareCompatibility
argument toStatementFactory::createFromAST()
.
2.3.0 - 2023-09-15
A stable release following release of Postgres 16. No code changes since beta.
2.3.0-beta - 2023-08-30
Support for new syntax of PostgreSQL 16 (as of beta 3)
- SQL/JSON functions and expressions:
IS JSON
predicate represented bynodes\expressions\IsJsonExpression
;- Aggregate functions
json_arrayagg()
andjson_objectagg()
represented bynodes\json\JsonArrayAgg
andnodes\json\JsonObjectAgg
; - Constructor functions
json_array()
andjson_object()
represented bynodes\json\JsonArrayValueList
,nodes\json\JsonArraySubselect
,nodes\json\JsonObject
classes.
- Allow non-decimal integer literals and underscores as separators in numeric literals.
- Aliases for subqueries in
FROM
are now optional. SYSTEM_USER
server variable backed bynodes\expressions\SQLValueFunction
.[NO] INDENT
option forXMLSERIALIZE()
expression.
2.2.0 - 2023-05-14
TypeNameNodeHandler
interface extendingTypeConverterFactory
frompg_wrapper
package: designed for factories that know how to processTypeName
nodes. Its methods were defined previously inParserAwareTypeConverterFactory
class which is now an implementation of the interface.BuilderSupportDecorator
class implementingTypeNameNodeHandler
and working as a decorator aroundDefaultTypeConverterFactory
.
ParserAwareTypeConverterFactory
is now deprecated, BuilderSupportDecorator
should be used instead.
2.1.0 - 2022-11-04
A stable release following release of Postgres 15. No code changes since beta 2.
2.1.0-beta.2 - 2022-10-09
Support for SQL/JSON syntax as it was removed in PostgreSQL 15 beta 4
2.1.0-beta - 2022-08-18
Support for new syntax of PostgreSQL 15:
MERGE
statementMerge
class andStatementFactory::merge()
helper method
- SQL/JSON functions and expressions
IS JSON
predicate represented bynodes\expressions\IsJsonExpression
;- Constructor functions
json()
,json_scalar()
,json_array()
,json_object()
represented bynodes\json\JsonConstructor
,nodes\json\JsonScalar
,nodes\json\JsonArray
,nodes\json\JsonObject
classes respectively; - Aggregate functions
json_arrayagg()
andjson_objectagg()
represented bynodes\json\JsonArrayAgg
andnodes\json\JsonObjectAgg
; - Query functions
json_exists()
,json_value()
,json_query()
represented bynodes\json\JsonExists
,nodes\json\JsonValue
,nodes\json\JsonQuery
; json_table()
expression appearing inFROM
clause represented bynodes\range\JsonTable
.
Reject numeric literals and positional parameters with trailing non-digits: previously SELECT 123abc
was parsed as
SELECT 123 AS abc
, now it will throw a SyntaxException
. This follows the changes to lexer done in Postgres 15.
2.0.1 - 2022-06-17
- Parser accepts
SELECT
queries with empty target lists (thanks to @rvanvelzen for PR #14).
2.0.0 - 2021-12-31
- Update dependencies, prevent using incompatible versions
- When caching parsed query fragments, a version is added to cache key to prevent loading
cache saved by previous version (e.g.
GroupByList
is now an abstract class and will cause an error if appearing in cache).
2.0.0-beta - 2021-11-19
Updated for Postgres 14 and PHP 8.1. The major version is incremented due to a few BC breaks.
- Support for new syntax of PostgreSQL 14:
- It is now possible to use most of the keywords as column aliases without
AS
. DISTINCT
clause forGROUP BY
. Exposed as$distinct
property for a newGroupByClause
node which is now used for$group
property ofSelect
.SEARCH
andCYCLE
clauses for Common Table Expressions. Implemented asSearchClause
andCycleClause
classes and exposed as$search
and$cycle
properties ofCommonTableExpression
class.- Alias can be specified for
USING
clause ofJOIN
expression. Exposed as$alias
property of a newUsingClause
node which is now used for$using
property ofJoinExpression
. SUBSTRING(string SIMILAR pattern ESCAPE escape)
function call, represented bynodes\expressions\SubstringSimilarExpression
- It is now possible to use most of the keywords as column aliases without
Several SQL standard functions with special arguments format (arguments separated by keywords or keywords as arguments, etc) were
previously parsed into FunctionExpression
with pg_catalog.internal_name
for a function name and a standard argument list,
they appeared that way in generated SQL: trim(trailing 'o' from 'foo')
-> pg_catalog.rtrim('foo', 'o')
.
These functions are now represented by separate Node
subclasses and will appear in generated SQL the same way they did in source.
The following functions were affected:
COLLATION FOR(...)
is now represented bynodes\expressions\CollationForExpression
EXTRACT(field FROM source)
-nodes\expressions\ExtractExpression
NORMALIZE(...)
-nodes\expressions\NormalizeExpression
OVERLAY(...)
-nodes\expressions\OverlayExpression
POSITION(...)
-nodes\expressions\PositionExpression
SUBSTRING(... FROM ...)
-nodes\expressions\SubstringFromExpression
TRIM(...)
-nodes\expressions\TrimExpression
XMLEXISTS(...)
-nodes\xml\XmlExists
This follows the changes done in Postgres 14. Note also that EXTRACT()
function maps to internal pg_catalog.extract()
in Postgres 14 while in previous versions it mapped to pg_catalog.date_part()
.
The package will run under PHP 8.1 with no E_DEPRECATED
messages:
- Added return type hints to implementations of methods from
ArrayAccess
,Countable
, andIteratorAggregate
interfaces. - Implemented
__serialize()
and__unserialize()
magic methods alongside methods defined in deprecatedSerializable
interface.
- Support for
IS [NOT] OF
expressions - Support for postfix operators
1.0.2 - 2021-08-10
A space before NOT
was missing when generating NOT BETWEEN
expressions.
1.0.1 - 2021-07-13
recursive
property of WithClause
was not properly set when passing SQL strings to its merge()
and replace()
methods.
1.0.0 - 2021-06-26
Support for undocumented IS [NOT] OF
expression that will be removed in Postgres 14.
1.0.0-beta - 2021-02-21
- Improved Unicode support
Lexer
handles\uXXXX
and\UXXXXXXXX
escapes in string literals with C-style escapes and converts them to UTF-8 strings.u&'...'
string literals andu&"..."
identifiers are also supported, including trailingUESCAPE
clauses. These are also converted to UTF-8.SqlBuilderWalker
has a new'escape_unicode'
option that will trigger converting multi-byte UTF-8 characters (i.e. non-ASCII) to Unicode escapes in generated SQL.
- It is now much easier to use the package for generating queries suitable for PDO:
StatementFactory
may be configured to keep:foo
named parameters, automatically escape?
in operator names and prevent generating dollar-quoted strings so that resultant SQL can be handed toPDO::prepare()
- Convenience method
StatementFactory::forPDO()
creates an instance ofStatementFactory
based on passed PDO connection (and enables the above compatibility) - New
ParserAwareTypeConverterFactory::convertParameters()
method prepares parameters forPDOStatement::execute()
using types info extracted from query
- Substantial performance improvements, especially when using cache. Tested on PHP 7.4 against version 0.4.1:
- 15-20% faster SQL parsing
- 25% faster SQL building
- 25% faster unserialization of AST and 30% smaller serialized data length
- 50% faster cloning of AST
- Tested and supported on PHP 8
- Static analysis with phpstan and psalm
- Special function-like constructs in
FROM
clause are now properly supported (Postgres allows these):select * from current_date, cast('PT1M' as interval);
- Package
Exception
interface now extends\Throwable
- Requires at least PHP 7.2
- Requires at least PostgreSQL 9.5
- Parser expects incoming SQL to be encoded in UTF-8, will throw exceptions in case of invalid encoding
- Method
mergeInputTypes()
ofNativeStatement
renamed tomergeParameterTypes()
- Changes to
StatementFactory
API- Constructor accepts an instance of
Parser
, an instance of class implementing newStatementToStringWalker
interface (which is implemented bySqlBuilderWalker
), and a flag to toggle PDO-compatible output. - Creation of
StatementFactory
configured forConnection
object frompg_wrapper
package is now done viaStatementFactory::forConnection()
method. - Similarly, an instance of
StatementFactory
configured forPDO
connection can be created withStatementFactory::forPDO()
.
- Constructor accepts an instance of
- Changes to
Node
subclasses API:- Methods
and_()
andor_()
ofWhereOrHavingClause
were renamed toand()
andor()
as such names are allowed in PHP 7 - Signatures of constructors for
ColumnReference
andQualifiedName
were changed from__construct(array $parts)
to__construct(...$parts)
OperatorExpression
no longer accepts any string as an operator, it accepts either a string of special characters valid for operator name or an instance of newQualifiedOperator
class representing a namespaced operator:operator(pg_catalog.+)
. SQL constructs previously represented byOperatorExpression
have their own nodes:AtTimeZoneExpression
,IsDistinctFromExpression
,IsExpression
,OverlapsExpression
,NotExpression
.- Similar to above,
FunctionCall
constructor will no longer accept a string with an SQL keyword for a function name and will convert a non-keyword string toQualifiedName
. ThusFunctionCall
's$name
property is always an instance ofQualifiedName
. Function-like constructs previously represented byFunctionCall
have their own nodes:ArrayComparisonExpression
(forANY
/ALL
/SOME
),NullIfExpression
,SystemFunctionCallExpression
(forCOALESCE
,GREATEST
,LEAST
,XMLCONCAT
) NOT
in SQL constructs likeIS NOT DISTINCT FROM
orNOT BETWEEN
is represented as$not
property of a relevantNode
Constant
andParameter
nodes were essentially 1:1 mapping ofTYPE_LITERAL
andTYPE_PARAMETER
Token
s exposingToken::TYPE_*
constants, so branching code was needed to process them. Added specializedKeywordConstant
,NumericConstant
,StringConstant
,NamedParameter
,PositionalParameter
child classes.Constant
andParameter
are now abstract base classes containing factory-like methods for creating child class instances.XmlColumnDefinition
(used in representingXMLTABLE
constructs) is now an abstract class extended byXmlOrdinalityColumnDefinition
andXmlTypedColumnDefinition
- SQL standard "value functions" like
current_user
andcurrent_timestamp
are represented by a newSQLValueFunction
Node instead of ad-hoc system function calls and typecasts. They will now appear in generated SQL the same way they did in source. ArrayIndexes
node representing a single offset access[1]
rather than slice[1:2]
will have that offset as an upper bound rather than lower.ArrayIndexes
will disallow setting lower bound for non-slice nodes.RowsFrom
no longer extendsrange\FunctionCall
, they both extend a new baseFunctionFromElement
class. Also property ofRowsFrom
containing function calls is named$functions
rather than$function
.
- Methods
- Changes to
TreeWalker
interfacewalkConstant()
was replaced bywalkKeywordConstant()
/walkNumericConstant()
/walkStringConstant()
methods.- Similarly,
walkParameter()
was replaced bywalkNamedParameter()
andwalkPositionalParameter()
. - Also
walkXmlColumnDefinition
was replaced bywalkXmlTypedColumnDefinition()
andwalkXmlOrdinalityColumnDefinition()
- Added
walkQualifiedOperator()
for visitingQualifiedOperator
nodes. - Added
walkAtTimeZoneExpression()
,walkIsDistinctFromExpression()
,walkIsExpression()
,walkNotExpression()
,walkOverlapsExpression()
for visiting nodes previously represented byOperatorExpression
. - Added
walkSQLValueFunction()
for visitingSQLValueFunction
nodes. - Added
walkSystemFunctionCall()
,walkArrayComparisonExpression()
,walkNullIfExpression()
for visiting nodes previously represented byFunctionCall
.
- Most of the required renames and changes to code that deals with creating objects can be automated by using the
provided rector rules, consult the upgrade instructions. Changes to custom
TreeWalker
implementations and to code that checks for particular object instances and property values should be done manually, unfortunately.
- As postfix operators are deprecated in Postgres 13 and will be removed in Postgres 14,
OperatorExpression
will now trigger a (silenced)E_USER_DEPRECATED
error when right operand is missing. Support for postfix operators will be removed altogether in the release of pg_builder that supports new syntax features of Postgres 14.
- Support for
mbstring.func_overload
, which was deprecated in PHP 7.2 - Support for operator precedence of pre-9.5 Postgres
'ascii_only_downcasing'
option forLexer
, it is now assumed to always betrue
- Single quotes in string literals with C-style escapes could be unescaped twice
- Subselect with several parentheses around it could be incorrectly parsed
and()
andor()
methods ofWhereOrHavingClause
incorrectly handled emptyWhereOrHavingClause
and emptyLogicalExpression
passed as arguments.BlankWalker
missed severaldispatch()
calls to child nodes
0.4.1 - 2020-09-30
SqlBuilderWalker
used incorrect operator precedence when generating SQL containing newIS NORMALIZED
operator- A sub-optimal regular expression in
Lexer
could cause up to 10x lexing slowdown for some queries
0.4.0 - 2020-09-26
This is the last feature release to support PHP 5 and Postgres versions below 9.5
- New keywords from Postgres 12 and 13
- Support for new syntax of Postgres 12:
MATERIALIZED
/NOT MATERIALIZED
modifiers of Common Table Expressions. Exposed as$materialized
property ofCommonTableExpression
node.BY VALUE
clause inXMLEXISTS
andXMLTABLE
.
- Support for new syntax of Postgres 13:
FETCH FIRST ... WITH TIES
form of SQL:2008 limit clause. Exposed as$limitWithTies
property ofSelectCommon
node.IS [NOT] NORMALIZED
operator.NORMALIZE(...)
function.
.gitattributes
file to prevent installing tests with the package
- Use composer's PSR-4 autoloaders for code and tests, drop home-grown ones
- Parsing of argument for SQL:2008 limit clause (
FETCH FIRST ...
) better follows behaviour of Postgres.
0.3.0 - 2018-10-30
- Support for new syntax of PostgreSQL 11
- Ported fixes to multicharacter operators processing from Postgres lexer
- Fixed
BlankWalker
(and consequentlyParameterWalker
) not visiting nodes representingON CONFLICT
clause ofINSERT
- PHPDoc cleanup
0.2.3 - 2018-10-28
Parser
clones parsedNode
objects when storing them in cache or retrieving from cache. This prevents problems if the same query fragment is used multiple times.- Make
ext-ctype
a required dependency incomposer.json
0.2.2 - 2017-10-05
- Invalid dollar-quoted strings created by
SqlBuilderWalker
if the string constant ended with dollar symbol (common thing with RegExps) - Make
sad-spirit/pg_wrapper
a suggested dependency incomposer.json
0.2.1 - 2017-09-19
- Support for
SKIP LOCKED
construct in locking clause ofSELECT
. Missed when implementing syntax of Postgres 9.5 BlankWalker
implementation ofTreeWalker
that only dispatches to child nodes.ParameterWalker
is reimplemented as a subclass ofBlankWalker
.
$statement
property ofCommonTableExpression
is now writable.
0.2.0 - 2017-09-04
- Support for new syntax of PostgreSQL versions 9.5, 9.6 and 10
Parser
can be configured to use either pre-9.5 or 9.5+ operator precedenceSqlBuilderWalker
can add parentheses in compatibility mode, so that generated queries will run on both pre-9.5 and 9.5+ PostgreSQL- Added
converters\ParserAwareTypeConverterFactory
that contains code depending onsad-spirit/pg-builder
classes
sad-spirit/pg-wrapper
is now an optional dependency, baseException
interface no longer extendssad_spirit\pg_wrapper\Exception
Parser
can now use any PSR-6 compatible cache implementation for storing generated ASTs, as home-grown cache implementation was removed frompg_wrapper
.
- Correctly build
WHERE
clause when first call toWhereOrHavingClause::and_()
contained an expression withOR
0.1.1 - 2014-10-06
Exceptions from sad-spirit/pg-wrapper
are no longer thrown here.
0.1.0 - 2014-09-28
Initial release on GitHub