Skip to content

Releases: decMuc/PDOdb

PDOdb v1.3.6 — Array parameter expansion (IN ...) refined

15 Aug 00:09

Choose a tag to compare

This update rewrites the internal expansion for array parameters used in IN (...) (and similar). It now strictly validates placeholder usage, supports reuse of named scalars across multiple SQL occurrences, and deterministically expands named arrays per occurrence. Positional arrays expand into N comma-separated ? as expected.

Why: more predictable bindings, clear errors on misuse, and safer defaults.

Added

  • Reuse of named scalar placeholders across multiple SQL occurrences.
  • Deterministic expansion of named array placeholders per occurrence: :name_{occIdx}_{elemIdx}.

Changed

  • Stricter validation of placeholder styles; named vs. positional must not be mixed.
  • Improved error messages and state reset on failure.

Fixed

  • Correct placeholder/parameter count checks for positional arrays.

Breaking

  • Empty arrays (named or positional) now throw.
  • Mixed named + positional in one query now throws.

PDOdb v1.3.5 – Improved Error Handling

29 Jul 00:20

Choose a tag to compare

Error Management Refactored

PDOdb has long followed an exception-based error handling model.
As of v1.3.5, this approach is now consistently enforced across all operations.

While ThingEngineer's MysqliDb provides basic error feedback, its behavior under try/catch can be unreliable in certain edge cases. For example, when errors occur inside loops or chained calls, the internal error state might not reset cleanly – and if the result is not checked manually, the application can continue in an invalid state.

In some cases, MysqliDb would not return anything in getLastError() simply because a fatal PHP error had already occurred before the error could be stored. Since no exception was thrown, try/catch could not intercept the failure, and the script terminated unexpectedly.

In contrast, PDOdb guarantees that all critical errors immediately throw an exception and are safely stored internally for later inspection. This allows developers to handle errors in a controlled and predictable way using standard try/catch blocks.

Exception-First Design

It’s now a design decision to prefer structured try/catch blocks in your application logic when using PDOdb.

This allows for precise error handling via either:

$e->getMessage() // Native PHP exception
$db->getLastError() // Internal message from PDOdb

Both approaches work seamlessly together.

Note on getLastError()

getLastError() may return the internal PDOdb error message or, in some cases, a raw SQL/PDO error depending on the failure context.
For most application-level handling, the recommended pattern remains:

try {
    $db->insert('table', $data);
} catch (\Throwable $e) {
    echo $db->getLastError(); // or $e->getMessage()
}

Version 1.3.4 – Extended Placeholders, Secure Values & Debug Improvements

19 Jul 04:28

Choose a tag to compare

This release includes extended placeholder support, improved value validation, and enhanced debug traceability.
It also introduces initial deprecation warnings for legacy property usage, preparing for safer and cleaner API usage in future versions.

Changes in v1.3.4

Added
Full support for special values in:

insert(), insertMulti(), update(), replace()

Central _secureValidateInsertValues() for consistent value validation

Automatic subquery alias mapping via host for use in secureHaving() and others

Security & Validation
Improved secureWhere():

Blocks unsafe SQL functions (SLEEP(), BENCHMARK(), etc.)

Disallows aggregate functions (SUM(...), AVG(...)) inside WHERE

Validates subqueries, nulls, arrays, and column names strictly

All per-connection settings (setPageLimit(), setReturnKey(), etc.) are now instance-safe

Debug & Logging
_lastDebugQuery now tracks queries even before reset or on failure

Full restoration of logQuery(), logException(), and handleException() across all queries

Logging improvements for WHERE, JOIN, and other clause types

⚠️ Deprecated (to be removed in v1.5.0)

  • $db->pageLimit
    → use setPageLimit() instead (instance-safe)

  • $db->map
    → use setReturnKey() instead

  • $db->arrayBuilder(), $db->objectBuilder(), $db->jsonBuilder()
    → use setOutputMode('array' | 'object' | 'json') instead

  • $db->escape()
    → remains a non-functional dummy and may be removed in a future version

  • Static global instance via getInstance()
    → use named instances via getInstance('your_name') instead

Note
This release is recommended for all users who rely on safe inserts, debug tracing, and subquery support.
Legacy property access will be phased out in upcoming versions – migrate early to ensure forward compatibility.

v1.3.3 – Optional heuristic WHERE check toggle added

14 Jul 03:07

Choose a tag to compare

Adds optional heuristic validation for suspicious WHERE values (e.g., SQL injection attempts).
Enabled by default; may add ~1–3 ms overhead in edge cases.
Can be disabled via:

define('PDOdb_HEURISTIC_WHERE_CHECK', false);

PDOdb Update: Improved Security – Successful SQL Injection Tests So Far!

12 Jul 04:22

Choose a tag to compare

This release focuses on readability and maintainability:

Completely reorganized class structure: methods are now logically grouped, clearly sorted, and easier to navigate.

Improved naming: some internal methods have been renamed for better clarity and consistency.

What's Next?
Sorting of internal _secure* methods is still pending. I'll tackle this within the next few days—no separate release planned, as it won't affect functionality. Just too lazy to finish it today!

Version Note: Why the jump from 1.3.0 to 1.3.2?
I intentionally skipped version 1.3.1 because I ran multiple internal/local tests under that number but never officially released it. When I was finally ready, significant additional improvements justified a direct jump to 1.3.2. This isn't a mistake—just a result of extensive local testing and limited publishing time!

PDOdb v1.3.0 – Cleanup & Compatibility Refinement

08 Jul 22:20

Choose a tag to compare

This release removes legacy methods inherited from the original ThingEngineer class and marks a small but important shift in project philosophy: PDOdb is now a "close to 1:1 logic-compatible" replacement, rather than a strict clone.

Removed
loadData() and loadXml()
These methods relied on LOAD DATA INFILE / LOAD XML INFILE, which are:

non-portable (require special server configuration and privileges)

bypass PDO's prepared statement model

considered unsafe in modern deployments

They were part of the original MysqliDb class but do not align with the design goals of PDOdb.
If needed, use native PHP CSV/XML handling with prepared inserts.

Added

Default instance name $instance = 'default'
This ensures stable fallback behavior when no named connection is specified.

Changed

README updated to reflect the removal of legacy import methods

Reworded compatibility statement: now described as "close to 1:1 compatible" for transparency

Hotfix - wrong namespace

07 Jul 02:50

Choose a tag to compare

Hotfix - wrong namespace

Release 1.2.2 — Named Instances & Connection Management

07 Jul 02:21

Choose a tag to compare

This update introduces named instances for full multi-connection support.

Added
instance support in constructor (new PDOdb([...])) and CustDB::createInstance(...)

PDOdb::getInstance('name') retrieves specific instances

subQuery() now inherits the correct instance automatically

Changed
Internal handling of $defConnectionName and $_activeInstanceName for accurate context

getInstance() now returns the last active or default instance cleanly

Note
If you omit the instance key, your new object won't be registered – it becomes a one-time use connection.

v1.2.0 – Deep SQL Expression Parsing & Injection Defense

03 Jul 21:26

Choose a tag to compare

[1.2.0] – 2025-07-03

Added

  • Full SQL expression validation for groupBy() and orderBy() methods
  • Security filter: Blocks dangerous SQL constructs (e.g. UNION, DROP, SLEEP, etc.)
  • Expression parser:
    • Nested function support (e.g. ROUND(ABS(price), 2))
    • CASE WHEN validation with deep inspection
    • Literal and operator detection (e.g. total > 100)
  • Extensive test coverage for allowed and blocked payloads

Changed

  • validateSqlExpression() is now used internally by groupBy() and orderBy() to enforce safe syntax
  • Removed internal $this->reset() call to avoid silent data loss between method calls

Fixed

  • Fixed missing exception in CASE WHEN expressions with invalid inner content
  • Proper handling of blocked ORDER BY RAND(), SLEEP(), DROP TABLE, and similar injection attempts

Version 1.1.0 – Type-safe WHERE Extensions

03 Jul 14:05

Choose a tag to compare

This release introduces several new where*() methods that allow for strict and type-safe filtering in your SQL queries – fully compatible with the existing API, but safer and more predictable when handling dynamic user input.

These extensions significantly improve SQL safety and prepare the foundation for type-specific logic in multi-tenant or user-facing environments.

✨ New Features (v1.1.0)
🔢 whereInt() / orWhereInt()
Strict integer filtering. Only clean integers are allowed.
Rejects invalid strings like "123abc" or injection attempts.

🔁 whereFloat() / orWhereFloat()
Strict float/decimal filtering. Accepts floats, integers, and numeric strings like "1.23".
Rejects malformed input and non-numeric values.

🔤 whereString() / orWhereString()
Filters only safe string values.
Blocks strings containing SQL control characters or known injection patterns.

✅ whereBool() / orWhereBool()
Strict boolean filtering. Accepts only true, false, 1, or 0.
All other values trigger an exception.

⚫️ whereIsNull() / orWhereIsNull()
Adds a IS NULL condition to the WHERE clause.

⚪️ whereIsNotNull() / orWhereIsNotNull()
Adds a IS NOT NULL condition to the WHERE clause.

📥 whereIn() / orWhereIn()
Filters using an IN (...) clause.
Accepts an array of scalar values and safely binds them via placeholders.

📤 whereNotIn() / orWhereNotIn()
Filters using a NOT IN (...) clause.
Also uses safe, parameterized bindings – input must be a non-empty array.

📚 Documentation
All new methods are documented in the updated README.md, including usage examples and input validation rules.

🧱 Internal
All where*() methods internally use secureWhere() for consistent query construction and prepared statement safety.

Version bumped from v1.0.3 to v1.1.0.

📄 Changelog

See CHANGELOG.md for a full list of changes and version history.