{"record":{"id":"ebd36590dd3036ad","repo":"phalcon/cphalcon","slug":"returning-requires-at-least-one-column-or","errorCode":null,"errorMessage":"RETURNING requires at least one column or '*'","messagePattern":"RETURNING requires at least one column or '\\*'","errorType":"exception","errorClass":"ReturningRequiresColumn","httpStatus":null,"severity":"error","filePath":"phalcon/Db/Dialect/Postgresql.zep","lineNumber":910,"sourceCode":"            if column->hasDefault() {\n                let defaultValue = this->castDefault(column);\n                let sql .= sqlAlterTable . \" ALTER COLUMN \\\"\" . column->getName() . \"\\\" SET DEFAULT \" . defaultValue;\n            }\n        }\n\n        return sql;\n    }\n\n    /**\n     * Appends a `RETURNING` clause to the supplied INSERT/UPDATE/DELETE\n     * statement. Pass `[\"*\"]` for `RETURNING *`, or a list of column names.\n     */\n    public function returning( string sqlQuery,  array columns) -> string\n    {\n        var first;\n\n        if unlikely empty columns {\n            throw new ReturningRequiresColumn();\n        }\n\n        if count(columns) == 1 {\n            let first = (string) columns[0];\n\n            if first == \"*\" {\n                return sqlQuery . \" RETURNING *\";\n            }\n        }\n\n        return sqlQuery . \" RETURNING \" . this->getColumnList(columns);\n    }\n\n    /**\n     * PostgreSQL supports materialized views (`CREATE MATERIALIZED VIEW`).\n     */\n    public function supportsMaterializedViews() -> bool\n    {","sourceCodeStart":892,"sourceCodeEnd":928,"githubUrl":"https://github.com/phalcon/cphalcon/blob/b7419de9cd0a8a3f48441ead84c9f8415d463e25/phalcon/Db/Dialect/Postgresql.zep#L892-L928","documentation":"The PostgreSQL dialect's returning() helper appends a RETURNING clause to an INSERT/UPDATE/DELETE and throws ReturningRequiresColumn when the columns array is empty. RETURNING with no column list is not valid PostgreSQL (there is no bare 'RETURNING' without a projection), so the helper demands at least one column name or the literal '*' as the single element.","triggerScenarios":"Calling $dialect->returning($sql, []) or returning($sql, array_filter($cols)) where the filter removed everything; building the column list from a variable that is null/empty, e.g. when no auto-generated columns were requested.","commonSituations":"Generic DAO layers that add RETURNING only when generated columns are configured and pass the empty list anyway; refactors that changed the default from ['*'] to []; request-driven column lists that arrive empty.","solutions":["Pass a non-empty list: returning($sql, ['*']) for all columns, or returning($sql, ['id', 'created_at'])","Skip the RETURNING clause entirely when you do not need returned columns instead of calling with an empty array","Default the list: $columns = $columns ?: ['*'] before the call"],"exampleFix":"// before\n$sql = $dialect->returning($insertSql, []);\n\n// after\n$sql = $dialect->returning($insertSql, ['*']);","handlingStrategy":"validation","validationCode":"if (empty($columns)) {\n    throw new InvalidArgumentException('RETURNING requires at least one column or \"*\"');\n}\n// or default: $columns = $columns ?: ['*'];","typeGuard":"function isNonEmptyColumnList(array $columns): bool\n{\n    return $columns !== [] && array_reduce($columns, fn($ok, $c) => $ok && is_string($c) && $c !== '', true);\n}","tryCatchPattern":"try {\n    $sql = $dialect->returning($sql, $columns);\n} catch (\\Phalcon\\Db\\Exceptions\\ReturningRequiresColumn $e) {\n    $sql = $dialect->returning($sql, ['*']); // or skip RETURNING\n}","preventionTips":["Default the RETURNING list to ['*'] in your DAO helper","Skip the RETURNING call when no columns are requested rather than passing []","Beware array_filter(): it can leave an empty list that was non-empty before"],"tags":["phalcon","postgresql","returning","ddl","validation"],"backgroundTag":"empty-required-parameter","analyzedSha":"b7419de9cd0a8a3f48441ead84c9f8415d463e25","analyzedAt":"2026-08-21T06:21:18.811Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}