diff --git a/phalcon/db/dialect.zep b/phalcon/db/dialect.zep index 37edb9b908b..db6fcbc70a3 100644 --- a/phalcon/db/dialect.zep +++ b/phalcon/db/dialect.zep @@ -14,6 +14,7 @@ +------------------------------------------------------------------------+ | Authors: Andres Gutierrez | | Eduar Carvajal | + | Stanislav Kiryukhin | +------------------------------------------------------------------------+ */ @@ -23,27 +24,65 @@ namespace Phalcon\Db; * Phalcon\Db\Dialect * * This is the base class to each database dialect. This implements - * common methods to transform intermediate code into its RDBM related syntax + * common methods to transform intermediate code into its RDBMS related syntax */ -abstract class Dialect +abstract class Dialect implements DialectInterface { protected _escapeChar; + /** + * Escape identifiers + */ + public final function escape(string! str, string escapeChar = null) -> string + { + var parts, key, part, isEscape; + + if escapeChar == "" { + let escapeChar = (string) this->_escapeChar; + } + + let parts = (array) explode(".", trim(str, escapeChar)); + let isEscape = (boolean) globals_get("db.escape_identifiers"); + + for key, part in parts { + + if escapeChar == "" || !isEscape || part == "" || part == "*" { + continue; + } + + let parts[key] = escapeChar . part . escapeChar; + } + + return implode(".", parts); + } + /** * Generates the SQL for LIMIT clause * - * - * $sql = $dialect->limit('SELECT * FROM robots', 10); - * echo $sql; // SELECT * FROM robots LIMIT 10 - * + * + * $sql = $dialect->limit('SELECT * FROM robots', 10); + * echo $sql; // SELECT * FROM robots LIMIT 10 + * + * $sql = $dialect->limit('SELECT * FROM robots', [10, 50]); + * echo $sql; // SELECT * FROM robots LIMIT 10 OFFSET 50 + * */ - public function limit(string! sqlQuery, int number) -> string + public function limit(string! sqlQuery, var number) -> string { - if is_numeric(number) { + if typeof number == "array" { + + let sqlQuery .= " LIMIT " . number[0]; + + if isset number[1] && strlen(number[1]) { + let sqlQuery .= " OFFSET " . number[1]; + } + + return sqlQuery; + + } else { return sqlQuery . " LIMIT " . number; } - return sqlQuery; } /** @@ -75,183 +114,175 @@ abstract class Dialect /** * Gets a list of columns with escaped identifiers * - * - * echo $dialect->getColumnList(array('column1', 'column')); - * + * + * echo $dialect->getColumnList(array('column1', 'column')); + * */ public final function getColumnList(array! columnList) -> string { - var strList, escapeChar, column; - let strList = [], - escapeChar = this->_escapeChar; + var columns, column; + let columns = []; + for column in columnList { - let strList[] = escapeChar . column . escapeChar; + let columns[] = this->getSqlColumn(column); } - return join(", ", strList); + + return join(", ", columns); } /** - * Transforms an intermediate representation for a expression into a database system valid expression - * - * @param array expression - * @param string escapeChar - * @return string + * Resolve Column expressions */ - public function getSqlExpression(array! expression, var escapeChar = null) -> string + public final function getSqlColumn(var column) -> string { - var type, domain, operator, left, right, name, sqlItems, - escapedName, sqlArguments, arguments, argument, item; + var columnExpression, columnAlias, columnField, columnDomain; - if globals_get("db.escape_identifiers") { - if escapeChar === null{ - let escapeChar = (string) this->_escapeChar; - } + if typeof column != "array" { + return this->prepareQualified(column); } - if !fetch type, expression["type"] { - throw new Exception("Invalid SQL expression"); - } + if !isset column["type"] { - /** - * Resolve qualified expressions - */ - if type == "qualified" { + /** + * The index "0" is the column field + */ + let columnField = column[0]; + + if typeof columnField == "array" { + let columnExpression = [ + "type": "scalar", + "value": columnField + ]; + + } elseif columnField == "*" { + let columnExpression = [ + "type": "all" + ]; - let name = expression["name"]; - if globals_get("db.escape_identifiers") { - let escapedName = escapeChar . name . escapeChar; } else { - let escapedName = name; + let columnExpression = [ + "type": "qualified", + "name": columnField + ]; } /** - * A domain could be a table/schema + * The index "1" is the domain column */ - if fetch domain, expression["domain"] { - if globals_get("db.escape_identifiers") { - return escapeChar . domain . escapeChar . "." . escapedName; - } else { - return domain . "." . escapedName; - } + if fetch columnDomain, column[1] && columnDomain != "" { + let columnExpression["domain"] = columnDomain; } - return escapedName; + /** + * The index "2" is the column alias + */ + if fetch columnAlias, column[2] && columnAlias { + let columnExpression["sqlAlias"] = columnAlias; + } + } else { + let columnExpression = column; } /** - * Resolve literal expressions + * Resolve column expressions */ - if type == "literal" { - return expression["value"]; - } + let column = this->getSqlExpression(columnExpression); /** - * Resolve binary operations expressions + * Escape alias and concatenate to value SQL */ - if type == "binary-op" { + if fetch columnAlias, columnExpression["sqlAlias"] || fetch columnAlias, columnExpression["alias"] { + return this->prepareColumnAlias(column, columnAlias); + } else { + return this->prepareColumnAlias(column); + } + } - let left = this->getSqlExpression(expression["left"], escapeChar), - right = this->getSqlExpression(expression["right"], escapeChar); + /** + * Transforms an intermediate representation for a expression into a database system valid expression + */ + public function getSqlExpression(array! expression, var escapeChar = null) -> string + { + var type; - return left . " " . expression["op"] . " " . right; + if !fetch type, expression["type"] { + throw new Exception("Invalid SQL expression"); } - /** - * Resolve unary operations expressions - */ - if type == "unary-op" { - - let operator = expression["op"]; + switch type { /** - * Some unary operators use the left operand... + * Resolve scalar column expressions */ - if fetch left, expression["left"] { - return this->getSqlExpression(left, escapeChar) . operator; - } + case "scalar": + return this->getSqlExpressionScalar(expression, escapeChar); /** - * ...Others use the right operand + * Resolve object expressions */ - if fetch right, expression["right"] { - return operator . this->getSqlExpression(right, escapeChar); - } - - throw new Exception("Invalid SQL-unary expression"); - } - - /** - * Resolve placeholder - */ - if type == "placeholder" { - return expression["value"]; - } + case "object": + return this->getSqlExpressionObject(expression, escapeChar); - /** - * Resolve parentheses - */ - if type == "parentheses" { - return "(" . this->getSqlExpression(expression["left"], escapeChar) . ")"; - } + /** + * Resolve qualified expressions + */ + case "qualified": + return this->getSqlExpressionQualified(expression, escapeChar); - /** - * Resolve function calls - */ - if type == "functionCall" { - let name = expression["name"], - sqlArguments = []; - if fetch arguments, expression["arguments"] { - for argument in arguments { - let sqlArguments[] = this->getSqlExpression(argument, escapeChar); - } - if isset expression["distinct"] { - return name . "(DISTINCT " . join(", ", sqlArguments) . ")"; - } else { - return name . "(" . join(", ", sqlArguments) . ")"; - } - return name . "(" . join(", ", sqlArguments) . ")"; - } - return name . "()"; - } + /** + * Resolve literal OR placeholder expressions + */ + case "literal": + case "placeholder": + return expression["value"]; - /** - * Resolve lists - */ - if type == "list" { - let sqlItems = []; - for item in expression[0] { - let sqlItems[] = this->getSqlExpression(item, escapeChar); - } - return "(" . join(", ", sqlItems) . ")"; - } + /** + * Resolve binary operations expressions + */ + case "binary-op": + return this->getSqlExpressionBinaryOperations(expression, escapeChar); - /** - * Resolve * - */ - if type == "all" { - return "*"; - } + /** + * Resolve unary operations expressions + */ + case "unary-op": + return this->getSqlExpressionUnaryOperations(expression, escapeChar); - /** - * Resolve CAST of values - */ - if type == "cast" { + /** + * Resolve parentheses + */ + case "parentheses": + return "(" . this->getSqlExpression(expression["left"], escapeChar) . ")"; - let left = this->getSqlExpression(expression["left"], escapeChar), - right = this->getSqlExpression(expression["right"], escapeChar); + /** + * Resolve function calls + */ + case "functionCall": + return this->getSqlExpressionFunctionCall(expression, escapeChar); - return "CAST(" . left . " AS " . right . ")"; - } + /** + * Resolve lists + */ + case "list": + return this->getSqlExpressionList(expression, escapeChar); - /** - * Resolve CONVERT of values encodings - */ - if type == "convert" { + /** + * Resolve * + */ + case "all": + return this->getSqlExpressionAll(expression, escapeChar); - let left = this->getSqlExpression(expression["left"], escapeChar), - right = this->getSqlExpression(expression["right"], escapeChar); + /** + * Resolve CAST of values + */ + case "cast": + return this->getSqlExpressionCastValue(expression, escapeChar); - return "CONVERT(" . left . " USING " . right . ")"; + /** + * Resolve CONVERT of values encodings + */ + case "convert": + return this->getSqlExpressionConvertValue(expression, escapeChar); } /** @@ -269,12 +300,7 @@ abstract class Dialect */ public final function getSqlTable(var table, string escapeChar = null) -> string { - var sqlTable, sqlSchema, aliasName, sqlTableAlias, - schemaName, tableName; - - if escapeChar === null{ - let escapeChar = (string) this->_escapeChar; - } + var tableName, schemaName, aliasName; if typeof table == "array" { @@ -283,48 +309,24 @@ abstract class Dialect */ let tableName = table[0]; - if globals_get("db.escape_identifiers") { - let sqlTable = escapeChar . tableName . escapeChar; - } else { - let sqlTable = tableName; - } - /** * The index "1" is the schema name */ - let schemaName = table[1]; - - if schemaName != null && schemaName != "" { - if globals_get("db.escape_identifiers") { - let sqlSchema = escapeChar . schemaName . escapeChar . "." . sqlTable; - } else { - let sqlSchema = schemaName . "." . sqlTable; - } - } else { - let sqlSchema = sqlTable; + if !fetch schemaName, table[1] { + let schemaName = null; } /** * The index "2" is the table alias */ - if fetch aliasName, table[2] { - if globals_get("db.escape_identifiers") { - let sqlTableAlias = sqlSchema . " AS " . escapeChar . aliasName . escapeChar; - } else { - let sqlTableAlias = sqlSchema . " AS " . aliasName; - } - } else { - let sqlTableAlias = sqlSchema; + if !fetch aliasName, table[2] { + let aliasName = null; } - return sqlTableAlias; - } - - if globals_get("db.escape_identifiers") { - return escapeChar . table . escapeChar; + return this->prepareTable(tableName, schemaName, aliasName, escapeChar); + } else { + return table; } - - return table; } /** @@ -332,14 +334,8 @@ abstract class Dialect */ public function select(array! definition) -> string { - var tables, columns, escapeChar, columnItem, column, - selectedColumns, columnSql, columnDomainSql, columnAlias, - selectedTables, sqlJoin, joinExpressions, joinCondition, - joinConditionsArray, tablesSql, columnDomain, columnAliasSql, - columnsSql, table, distinct, sql, joins, join, sqlTable, whereConditions, - groupFields, groupField, groupItems, havingConditions, - orderFields, orderItem, orderItems, orderSqlItem, sqlOrderType, - orderSqlItemType, limitValue, limitNumber, limitNumberValue, offset, offsetNumber; + var tables, columns, sql; + var distinct, joins, where, groupBy, having, orderBy, limit; if !fetch tables, definition["tables"] { throw new Exception("The index 'tables' is required in the definition array"); @@ -349,271 +345,544 @@ abstract class Dialect throw new Exception("The index 'columns' is required in the definition array"); } - if globals_get("db.escape_identifiers") { - let escapeChar = this->_escapeChar; + if fetch distinct, definition["distinct"] { + + if distinct { + let sql = "SELECT DISTINCT"; + } else { + let sql = "SELECT ALL"; + } + } else { - let escapeChar = null; + let sql = "SELECT"; } - if typeof columns == "array" { + /** + * Resolve COLUMNS + */ + let sql .= " " . this->getColumnList(columns); - let selectedColumns = []; - for column in columns { + /** + * Resolve FROM + */ + let sql .= " " . this->getSqlExpressionFrom(tables); - /** - * Escape column name - */ - let columnItem = column[0]; - if typeof columnItem == "array" { - let columnSql = this->getSqlExpression(columnItem, escapeChar); - } else { - if columnItem == "*" { - let columnSql = columnItem; - } else { - if globals_get("db.escape_identifiers") { - let columnSql = escapeChar . columnItem . escapeChar; - } else { - let columnSql = columnItem; - } - } - } + /** + * Resolve JOINs + */ + if fetch joins, definition["joins"] && joins { + let sql .= " " . this->getSqlExpressionJoins(definition["joins"]); + } - /** - * Escape column domain - */ - if fetch columnDomain, column[1] { - if columnDomain { - if globals_get("db.escape_identifiers") { - let columnDomainSql = escapeChar . columnDomain . escapeChar . "." . columnSql; - } else { - let columnDomainSql = columnDomain . "." . columnSql; - } - } else { - let columnDomainSql = columnSql; - } - } else { - let columnDomainSql = columnSql; - } + /** + * Resolve WHERE + */ + if fetch where, definition["where"] && where { + let sql .= " " . this->getSqlExpressionWhere(where); + } - /** - * Escape column alias - */ - if fetch columnAlias, column[2] { - if columnAlias { - if globals_get("db.escape_identifiers") { - let columnAliasSql = columnDomainSql . " AS " . escapeChar . columnAlias . escapeChar; - } else { - let columnAliasSql = columnDomainSql . " AS " . columnAlias; - } - } else { - let columnAliasSql = columnDomainSql; - } - } else { - let columnAliasSql = columnDomainSql; - } - let selectedColumns[] = columnAliasSql; - } - let columnsSql = join(", ", selectedColumns); - } else { - let columnsSql = columns; + /** + * Resolve GROUP BY + */ + if fetch groupBy, definition["group"] && groupBy { + let sql .= " " . this->getSqlExpressionGroupBy(groupBy); } /** - * Check and escape tables + * Resolve HAVING */ - if typeof tables == "array" { - let selectedTables = []; - for table in tables { - let selectedTables[] = this->getSqlTable(table, escapeChar); - } - let tablesSql = join(", ", selectedTables); - } else { - let tablesSql = tables; + if fetch having, definition["having"] && having { + let sql .= " " . this->getSqlExpressionHaving(having); } - if fetch distinct, definition["distinct"] { - if distinct == 0 { - let sql = "SELECT ALL "; - } else { - if distinct == 1 { - let sql = "SELECT DISTINCT "; - } else { - let sql = "SELECT "; - } - } + /** + * Resolve ORDER BY + */ + if fetch orderBy, definition["order"] && orderBy { + let sql .= " " . this->getSqlExpressionOrderBy(orderBy); + } + + /** + * Resolve LIMIT + */ + if fetch limit, definition["limit"] && limit { + let sql = this->getSqlExpressionLimit(["sql": sql, "value": limit]); + } + + return sql; + } + + /** + * Checks whether the platform supports savepoints + */ + public function supportsSavepoints() -> boolean + { + return true; + } + + /** + * Checks whether the platform supports releasing savepoints. + */ + public function supportsReleaseSavepoints() -> boolean + { + return this->supportsSavePoints(); + } + + /** + * Generate SQL to create a new savepoint + */ + public function createSavepoint(string! name) -> string + { + return "SAVEPOINT " . name; + } + + /** + * Generate SQL to release a savepoint + */ + public function releaseSavepoint(string! name) -> string + { + return "RELEASE SAVEPOINT " . name; + } + + /** + * Generate SQL to rollback a savepoint + */ + public function rollbackSavepoint(string! name) -> string + { + return "ROLLBACK TO SAVEPOINT " . name; + } + + /** + * Resolve Column expressions + */ + protected final function getSqlExpressionScalar(array! expression, string escapeChar = null) -> string + { + var value; + + if isset expression["column"] { + return this->getSqlColumn(expression["column"]); + } + + if !fetch value, expression["value"] { + throw new Exception("Invalid SQL expression"); + } + + if typeof value == "array" { + return this->getSqlExpression(value, escapeChar); } else { - let sql = "SELECT "; + return value; + } + } + + /** + * Resolve object expressions + */ + protected final function getSqlExpressionObject(array! expression, string escapeChar = null) -> string + { + var domain = null, objectExpression; + + let objectExpression = [ + "type": "all" + ]; + + if (fetch domain, expression["balias"] || fetch domain, expression["domain"]) && domain != "" { + let objectExpression["domain"] = domain; } - let sql = sql . columnsSql . " FROM " . tablesSql; + return this->getSqlExpression(objectExpression, escapeChar); + } + +/** + * Resolve qualified expressions + */ + protected final function getSqlExpressionQualified(array! expression, string escapeChar = null) -> string + { + var column, domain; + let column = expression["name"]; /** - * Check for joins + * A domain could be a table/schema */ - if fetch joins, definition["joins"] { - for join in joins { + if !fetch domain, expression["domain"] { + let domain = null; + } - let sqlTable = this->getSqlTable(join["source"], escapeChar), - selectedTables[] = sqlTable, - sqlJoin = " " . join["type"] . " JOIN " . sqlTable; + return this->prepareQualified(column, domain, escapeChar); + } - /** - * Check if the join has conditions - */ - if fetch joinConditionsArray, join["conditions"] { - if count(joinConditionsArray) { - if !isset joinConditionsArray[0] { - let sqlJoin .= " ON " . this->getSqlExpression(joinConditionsArray, escapeChar) . " "; - } else { - let joinExpressions = []; - for joinCondition in joinConditionsArray { - let joinExpressions[] = this->getSqlExpression(joinCondition, escapeChar); - } - let sqlJoin .= " ON " . join(" AND ", joinExpressions) . " "; - } - } - } - let sql .= sqlJoin; - } + /** + * Resolve binary operations expressions + */ + protected final function getSqlExpressionBinaryOperations(array! expression, string escapeChar = null) -> string + { + var left, right; + + let left = this->getSqlExpression(expression["left"], escapeChar), + right = this->getSqlExpression(expression["right"], escapeChar); + + return left . " " . expression["op"] . " " . right; + } + + /** + * Resolve unary operations expressions + */ + protected final function getSqlExpressionUnaryOperations(array! expression, string escapeChar = null) -> string + { + var left, right; + + /** + * Some unary operators use the left operand... + */ + if fetch left, expression["left"] { + return this->getSqlExpression(left, escapeChar) . " " . expression["op"]; } /** - * Check for a WHERE clause + * ...Others use the right operand */ - if fetch whereConditions, definition["where"] { - if typeof whereConditions == "array" { - let sql .= " WHERE " . this->getSqlExpression(whereConditions, escapeChar); + if fetch right, expression["right"] { + return expression["op"] . " " . this->getSqlExpression(right, escapeChar); + } + + throw new Exception("Invalid SQL-unary expression"); + } + + /** + * Resolve function calls + */ + protected final function getSqlExpressionFunctionCall(array! expression, string escapeChar = null) -> string + { + var arguments; + + if fetch arguments, expression["arguments"] && typeof arguments == "array" { + + let arguments = this->getSqlExpression([ + "type": "list", + "parentheses": false, + "value": arguments + ], escapeChar); + + if isset expression["distinct"] && expression["distinct"] { + return expression["name"] . "(DISTINCT " . arguments . ")"; } else { - let sql .= " WHERE " . whereConditions; + return expression["name"] . "(" . arguments . ")"; } + } - /** - * Check for a GROUP clause - */ - if fetch groupFields, definition["group"]{ + return expression["name"] . "()"; + } - let groupItems = []; - for groupField in groupFields { - if typeof groupField == "array" { - let groupItems[] = this->getSqlExpression(groupField, escapeChar); - } else { - throw new Exception("?"); - } + /** + * Resolve Lists + */ + protected final function getSqlExpressionList(array! expression, string escapeChar = null) -> string + { + var items, item, values, separator; + + let items = []; + let separator = ", "; + + if isset expression["separator"] { + let separator = expression["separator"]; + } + + if (fetch values, expression[0] || fetch values, expression["value"]) && typeof values == "array" { + + for item in values { + let items[] = this->getSqlExpression(item, escapeChar); + } + + if isset expression["parentheses"] && expression["parentheses"] === false { + return join(separator, items); + } else { + return "(" . join(separator, items) . ")"; } - let sql .= " GROUP BY " . join(", ", groupItems); + } + + throw new Exception("Invalid SQL-list expression"); + } + + /** + * Resolve * + */ + protected final function getSqlExpressionAll(array! expression, string escapeChar = null) -> string + { + var domain; + + if !fetch domain, expression["domain"] { + let domain = null; + } + + return this->prepareQualified("*", domain, escapeChar); + } + + /** + * Resolve CAST of values + */ + protected final function getSqlExpressionCastValue(array! expression, string escapeChar = null) -> string + { + var left, right; + + let left = this->getSqlExpression(expression["left"], escapeChar), + right = this->getSqlExpression(expression["right"], escapeChar); + + return "CAST(" . left . " AS " . right . ")"; + } + + /** + * Resolve CONVERT of values encodings + */ + protected final function getSqlExpressionConvertValue(array! expression, string escapeChar = null) -> string + { + var left, right; + + let left = this->getSqlExpression(expression["left"], escapeChar), + right = this->getSqlExpression(expression["right"], escapeChar); + + return "CONVERT(" . left . " USING " . right . ")"; + } + + /** + * Resolve a FROM clause + */ + protected final function getSqlExpressionFrom(var expression, string escapeChar = null) -> string + { + var table, tables; + + if typeof expression == "array" { + + let tables = []; + + for table in expression { + let tables[] = this->getSqlTable(table); + } + + let tables = join(", ", tables); + + } else { + let tables = expression; + } + + return "FROM " . tables; + } + + /** + * Resolve a JOINs clause + */ + protected final function getSqlExpressionJoins(var expression, string escapeChar = null) -> string + { + var join, sql = "", joinCondition, joinTable, joinType = "", joinConditionsArray; + + for join in expression { /** - * Check for a HAVING clause + * Check if the join has conditions */ - if fetch havingConditions, definition["having"] { - if typeof havingConditions == "array" { - let sql .= " HAVING " . this->getSqlExpression(havingConditions, escapeChar); + if fetch joinConditionsArray, join["conditions"] && !empty joinConditionsArray { + + if !isset joinConditionsArray[0] { + let joinCondition = this->getSqlExpression(joinConditionsArray, escapeChar); } else { - throw new Exception("?"); + + var condition; + let joinCondition = []; + + for condition in joinConditionsArray { + let joinCondition[] = this->getSqlExpression(condition, escapeChar); + } + + let joinCondition = join(" AND ", joinCondition); } + } else { + let joinCondition = 1; + } + + if fetch joinType, join["type"] && joinType { + let joinType .= " "; } + + let joinTable = this->getSqlTable(join["source"], escapeChar); + + let sql .= " " . joinType . "JOIN " . joinTable . " ON " . joinCondition; } - /** - * Check for a ORDER clause - */ - if fetch orderFields, definition["order"]{ - let orderItems = []; - for orderItem in orderFields { + return sql; + } - if typeof orderItem == "array" { - let orderSqlItem = this->getSqlExpression(orderItem[0], escapeChar); - } else { - throw new Exception("?"); - } + /** + * Resolve a WHERE clause + */ + protected final function getSqlExpressionWhere(var expression, string escapeChar = null) -> string + { + var whereSql; - /** - * In the numeric 1 position could be a ASC/DESC clause - */ - if fetch sqlOrderType, orderItem[1] { - let orderSqlItemType = orderSqlItem . " " . sqlOrderType; + if typeof expression == "array" { + let whereSql = this->getSqlExpression(expression, escapeChar); + } else { + let whereSql = expression; + } + + return "WHERE " . whereSql; + } + + /** + * Resolve a GROUP BY clause + */ + protected final function getSqlExpressionGroupBy(var expression, string escapeChar = null) -> string + { + var filed, fields; + + if typeof expression == "array" { + + let fields = []; + + for filed in expression { + if unlikely typeof filed != "array" { + throw new Exception("Invalid SQL-GROUP-BY expression"); } else { - let orderSqlItemType = orderSqlItem; + let fields[] = this->getSqlExpression(filed, escapeChar); } - - let orderItems[] = orderSqlItemType; } - let sql .= " ORDER BY " . join(", ", orderItems); + + let fields = join(", ", fields); + + } else { + let fields = expression; } - /** - * Check for a LIMIT condition - */ - if fetch limitValue, definition["limit"] { + return "GROUP BY " . fields; + } + + /** + * Resolve a HAVING clause + */ + protected final function getSqlExpressionHaving(var expression, string escapeChar = null) -> string + { + if typeof expression == "array" { + return "HAVING " . this->getSqlExpression(expression, escapeChar); + } else { + throw new Exception("Invalid SQL-HAVING expression"); + } + } + + /** + * Resolve a ORDER BY clause + */ + protected final function getSqlExpressionOrderBy(var expression, string escapeChar = null) -> string + { + var filed, fields, type, fieldSql = null; + + if typeof expression == "array" { + + let fields = []; - if typeof limitValue == "array" { + for filed in expression { - let limitNumberValue = limitValue["number"]; - if typeof limitNumberValue == "array" { - let limitNumber = this->getSqlExpression(limitNumberValue, escapeChar); + if unlikely typeof filed != "array" { + throw new Exception("Invalid SQL-ORDER-BY expression"); } else { - let limitNumber = limitNumberValue; + let fieldSql = this->getSqlExpression(filed[0], escapeChar); } /** - * Check for a OFFSET condition + * In the numeric 1 position could be a ASC/DESC clause */ - if fetch offset, limitValue["offset"] { - if typeof offset == "array" { - let offsetNumber = this->getSqlExpression(offset, escapeChar); - } else { - let offsetNumber = offset; - } - let sql .= " LIMIT " . limitNumber . " OFFSET " . offsetNumber; - } else { - let sql .= " LIMIT " . limitNumber; + if fetch type, filed[1] && type != "" { + let fieldSql .= " " . type; } - } else { - let sql .= " LIMIT " . limitValue; + + let fields[] = fieldSql; } + + let fields = join(", ", fields); + + } else { + let fields = expression; } - return sql; + return "ORDER BY " . fields; } /** - * Checks whether the platform supports savepoints + * Resolve a LIMIT clause */ - public function supportsSavepoints() -> boolean + protected final function getSqlExpressionLimit(var expression, string escapeChar = null) -> string { - return true; - } + var sql = "", value, limit, offset = null; + let value = expression["value"]; - /** - * Checks whether the platform supports releasing savepoints. - */ - public function supportsReleaseSavepoints() -> boolean - { - return this->supportsSavePoints(); + if isset expression["sql"] { + let sql = expression["sql"]; + } + + if typeof value == "array" { + + if typeof value["number"] == "array" { + let limit = this->getSqlExpression(value["number"]); + } else { + let limit = value["number"]; + } + + /** + * Check for a OFFSET condition + */ + if fetch offset, value["offset"] && typeof offset == "array" { + let offset = this->getSqlExpression(offset); + } + + } else { + let limit = value; + } + + return this->limit(sql, [limit, offset]); } /** - * Generate SQL to create a new savepoint + * Prepares column for this RDBMS */ - public function createSavepoint(string! name) -> string + protected function prepareColumnAlias(string! qualified, string alias = null) -> string { - return "SAVEPOINT " . name; + if alias != "" { + return qualified . " AS " . this->escape(alias); + } else { + return qualified; + } } /** - * Generate SQL to release a savepoint + * Prepares table for this RDBMS */ - public function releaseSavepoint(string! name) -> string + protected function prepareTable(string! table, string schema = null, string alias = null, string escapeChar = null) -> string { - return "RELEASE SAVEPOINT " . name; + let table = this->escape(table, escapeChar); + + /** + * Schema + */ + if schema != "" { + let table = this->escape(schema, escapeChar) . "." . table; + } + + /** + * Alias + */ + if alias != "" { + let table = table . " AS " . this->escape(alias, escapeChar); + } + + return table; } /** - * Generate SQL to rollback a savepoint + * Prepares qualified for this RDBMS */ - public function rollbackSavepoint(string! name) -> string + protected function prepareQualified(string! column, string domain = null, string escapeChar = null) -> string { - return "ROLLBACK TO SAVEPOINT " . name; + if domain != "" { + return this->escape(domain . "." . column, escapeChar); + } else { + return this->escape(column, escapeChar); + } } } diff --git a/phalcon/db/dialect/mysql.zep b/phalcon/db/dialect/mysql.zep index 7aae909e373..282a92b0dc7 100644 --- a/phalcon/db/dialect/mysql.zep +++ b/phalcon/db/dialect/mysql.zep @@ -30,9 +30,9 @@ use Phalcon\Db\DialectInterface; /** * Phalcon\Db\Dialect\Mysql * - * Generates database specific SQL for the MySQL RBDM + * Generates database specific SQL for the MySQL RDBMS */ -class MySQL extends Dialect implements DialectInterface +class MySQL extends Dialect { protected _escapeChar = "`"; @@ -218,7 +218,7 @@ class MySQL extends Dialect implements DialectInterface /** * Generates SQL to delete a column from a table */ - public function dropColumn(string! tableName, string! schemaName, string columnName) -> string + public function dropColumn(string! tableName, string! schemaName, string! columnName) -> string { var sql; @@ -274,7 +274,7 @@ class MySQL extends Dialect implements DialectInterface /** * Generates SQL to add the primary key to a table */ - public function addPrimaryKey(string tableName, string schemaName, index) -> string + public function addPrimaryKey(string! tableName, string! schemaName, index) -> string { var sql; @@ -342,13 +342,8 @@ class MySQL extends Dialect implements DialectInterface /** * Generates SQL to delete a foreign key from a table - * - * @param string tableName - * @param string schemaName - * @param string referenceName - * @return string */ - public function dropForeignKey(string! tableName, string! schemaName, referenceName) -> string + public function dropForeignKey(string! tableName, string! schemaName, string! referenceName) -> string { var sql; if schemaName { @@ -360,59 +355,7 @@ class MySQL extends Dialect implements DialectInterface } /** - * Generates SQL to add the table creation options - * - * @param array definition - * @return array - */ - protected function _getTableOptions(definition) -> string - { - var options, engine, autoIncrement, tableCollation, - collationParts, tableOptions; - - if fetch options, definition["options"] { - - let tableOptions = []; - - /** - * Check if there is an ENGINE option - */ - if fetch engine, options["ENGINE"] { - if engine { - let tableOptions[] = "ENGINE=" . engine; - } - } - - /** - * Check if there is an AUTO_INCREMENT option - */ - if fetch autoIncrement, options["AUTO_INCREMENT"] { - if autoIncrement { - let tableOptions[] = "AUTO_INCREMENT=" . autoIncrement; - } - } - - /** - * Check if there is a TABLE_COLLATION option - */ - if fetch tableCollation, options["TABLE_COLLATION"] { - if tableCollation { - let collationParts = explode("_", tableCollation), - tableOptions[] = "DEFAULT CHARSET=" . collationParts[0], - tableOptions[] = "COLLATE=" . tableCollation; - } - } - - if count(tableOptions) { - return join(" ", tableOptions); - } - } - - return ""; - } - - /** - * Generates SQL to create a table in MySQL + * Generates SQL to create a table */ public function createTable(string! tableName, string! schemaName, array! definition) -> string { @@ -540,14 +483,9 @@ class MySQL extends Dialect implements DialectInterface } /** - * Generates SQL to drop a table - * - * @param string tableName - * @param string schemaName - * @param boolean ifExists - * @return string + * Generates SQL to drop a view */ - public function dropTable(string! tableName, string! schemaName, ifExists = true) -> string + public function dropTable(string! tableName, string schemaName = null, boolean! ifExists = true) -> string { var sql, table; @@ -568,13 +506,8 @@ class MySQL extends Dialect implements DialectInterface /** * Generates SQL to create a view - * - * @param string viewName - * @param array definition - * @param string schemaName - * @return string */ - public function createView(string! viewName, definition, string! schemaName) -> string + public function createView(string! viewName, array! definition, string schemaName = null) -> string { var view, viewSql; @@ -594,7 +527,7 @@ class MySQL extends Dialect implements DialectInterface /** * Generates SQL to drop a view */ - public function dropView(string! viewName, string! schemaName, boolean ifExists = true) -> string + public function dropView(string! viewName, string schemaName = null, boolean! ifExists = true) -> string { var sql, view; @@ -617,15 +550,11 @@ class MySQL extends Dialect implements DialectInterface * Generates SQL checking for the existence of a schema.table * * - * echo $dialect->tableExists("posts", "blog"); - * echo $dialect->tableExists("posts"); + * echo $dialect->tableExists("posts", "blog"); + * echo $dialect->tableExists("posts"); * - * - * @param string tableName - * @param string schemaName - * @return string */ - public function tableExists(string! tableName, schemaName = null) -> string + public function tableExists(string! tableName, string schemaName = null) -> string { if schemaName { return "SELECT IF(COUNT(*)>0, 1 , 0) FROM `INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_NAME`= '" . tableName . "' AND `TABLE_SCHEMA` = '" . schemaName . "'"; @@ -635,12 +564,8 @@ class MySQL extends Dialect implements DialectInterface /** * Generates SQL checking for the existence of a schema.view - * - * @param string viewName - * @param string schemaName - * @return string */ - public function viewExists(string! viewName, schemaName = null) -> string + public function viewExists(string! viewName, string schemaName = null) -> string { if schemaName { return "SELECT IF(COUNT(*)>0, 1 , 0) FROM `INFORMATION_SCHEMA`.`VIEWS` WHERE `TABLE_NAME`= '" . viewName . "' AND `TABLE_SCHEMA`='" . schemaName . "'"; @@ -651,15 +576,11 @@ class MySQL extends Dialect implements DialectInterface /** * Generates SQL describing a table * - * - * print_r($dialect->describeColumns("posts")); - * - * - * @param string table - * @param string schema - * @return string + * + * print_r($dialect->describeColumns("posts")); + * */ - public function describeColumns(string! table, schema = null) -> string + public function describeColumns(string! table, string schema = null) -> string { if schema { return "DESCRIBE `" . schema . "`.`" . table . "`"; @@ -670,11 +591,11 @@ class MySQL extends Dialect implements DialectInterface /** * List all tables in database * - * - * print_r($dialect->listTables("blog")) - * + * + * print_r($dialect->listTables("blog")) + * */ - public function listTables(string! schemaName = null) -> string + public function listTables(string schemaName = null) -> string { if schemaName { return "SHOW TABLES FROM `" . schemaName . "`"; @@ -695,12 +616,8 @@ class MySQL extends Dialect implements DialectInterface /** * Generates SQL to query indexes on a table - * - * @param string table - * @param string schema - * @return string */ - public function describeIndexes(string! table, schema = null) -> string + public function describeIndexes(string! table, string schema = null) -> string { if schema { return "SHOW INDEXES FROM `" . schema . "`.`" . table . "`"; @@ -710,12 +627,8 @@ class MySQL extends Dialect implements DialectInterface /** * Generates SQL to query foreign keys on a table - * - * @param string table - * @param string schema - * @return string */ - public function describeReferences(string! table, schema = null) -> string + public function describeReferences(string! table, string schema = null) -> string { var sql = "SELECT TABLE_NAME,COLUMN_NAME,CONSTRAINT_NAME,REFERENCED_TABLE_SCHEMA,REFERENCED_TABLE_NAME,REFERENCED_COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE REFERENCED_TABLE_NAME IS NOT NULL AND "; if schema { @@ -728,12 +641,8 @@ class MySQL extends Dialect implements DialectInterface /** * Generates the SQL to describe the table creation options - * - * @param string table - * @param string schema - * @return string */ - public function tableOptions(string! table, schema = null) -> string + public function tableOptions(string! table, string schema = null) -> string { var sql = "SELECT TABLES.TABLE_TYPE AS table_type,TABLES.AUTO_INCREMENT AS auto_increment,TABLES.ENGINE AS engine,TABLES.TABLE_COLLATION AS table_collation FROM INFORMATION_SCHEMA.TABLES WHERE "; if schema { @@ -741,4 +650,53 @@ class MySQL extends Dialect implements DialectInterface } return sql . "TABLES.TABLE_NAME = '" . table . "'"; } + + /** + * Generates SQL to add the table creation options + */ + protected function _getTableOptions(array! definition) -> string + { + var options, engine, autoIncrement, tableCollation, + collationParts, tableOptions; + + if fetch options, definition["options"] { + + let tableOptions = []; + + /** + * Check if there is an ENGINE option + */ + if fetch engine, options["ENGINE"] { + if engine { + let tableOptions[] = "ENGINE=" . engine; + } + } + + /** + * Check if there is an AUTO_INCREMENT option + */ + if fetch autoIncrement, options["AUTO_INCREMENT"] { + if autoIncrement { + let tableOptions[] = "AUTO_INCREMENT=" . autoIncrement; + } + } + + /** + * Check if there is a TABLE_COLLATION option + */ + if fetch tableCollation, options["TABLE_COLLATION"] { + if tableCollation { + let collationParts = explode("_", tableCollation), + tableOptions[] = "DEFAULT CHARSET=" . collationParts[0], + tableOptions[] = "COLLATE=" . tableCollation; + } + } + + if count(tableOptions) { + return join(" ", tableOptions); + } + } + + return ""; + } } diff --git a/phalcon/db/dialect/oracle.zep b/phalcon/db/dialect/oracle.zep index 15ceeb670c8..00546eba669 100644 --- a/phalcon/db/dialect/oracle.zep +++ b/phalcon/db/dialect/oracle.zep @@ -15,17 +15,378 @@ | Authors: Andres Gutierrez | | Eduar Carvajal | | Marcio Paiva | + | Stanislav Kiryukhin | +------------------------------------------------------------------------+ */ namespace Phalcon\Db\Dialect; +use Phalcon\Db\Dialect; +use Phalcon\Db\Column; +use Phalcon\Db\Exception; +use Phalcon\Db\IndexInterface; +use Phalcon\Db\ColumnInterface; +use Phalcon\Db\ReferenceInterface; +use Phalcon\Text; + /** * Phalcon\Db\Dialect\Oracle * - * Generates database specific SQL for the Oracle RBDM + * Generates database specific SQL for the Oracle RDBMS */ -class Oracle extends \Phalcon\Db\Dialect //implements Phalcon\Db\DialectInterface +class Oracle extends Dialect { protected _escapeChar = ""; + + /** + * Generates the SQL for LIMIT clause + */ + public function limit(string! sqlQuery, var number) -> string + { + var limit, offset = 0; + + if typeof number == "array" { + + if isset number[1] { + let offset = (int) trim(number[1], "'"); + } + + let limit = (int)trim(number[0], "'") + offset; + } else { + let limit = (int)trim(number, "'"); + } + + + let sqlQuery = "SELECT * FROM (SELECT Z1.*, ROWNUM PHALCON_RN FROM (" . sqlQuery . ") Z1 WHERE ROWNUM <= " . limit . ")"; + + if (offset != 0) { + let sqlQuery .= " WHERE PHALCON_RN >= " . offset; + } + + return sqlQuery; + } + + /** + * Gets the column name in Oracle + */ + public function getColumnDefinition( column) -> string + { + var columnSql, size, scale, type; + + let type = column->getType(); + let size = column->getSize(); + + switch type { + + case Column::TYPE_INTEGER: + let columnSql = "INTEGER"; + break; + + case Column::TYPE_DATE: + let columnSql = "DATE"; + break; + + case Column::TYPE_VARCHAR: + let columnSql = "VARCHAR2(" . size . ")"; + break; + + case Column::TYPE_DECIMAL: + let scale = column->getScale(); + let columnSql = "NUMBER(" . size . "," . scale . ")"; + break; + + case Column::TYPE_DATETIME: + let columnSql = "TIMESTAMP"; + break; + + case Column::TYPE_CHAR: + let columnSql = "CHAR(" . size . ")"; + break; + + case Column::TYPE_TEXT: + let columnSql = "TEXT"; + break; + + case Column::TYPE_FLOAT: + let scale = column->getScale(); + let columnSql = "FLOAT(" . size . "," . scale .")"; + break; + + case Column::TYPE_BOOLEAN: + let columnSql = "TINYINT(1)"; + break; + + default: + throw new Exception("Unrecognized Oracle data type"); + } + + return columnSql; + } + + /** + * Generates SQL to add a column to a table + */ + public function addColumn(string! tableName, string! schemaName, column) -> string + { + throw new Exception("Not implemented yet"); + } + + /** + * Generates SQL to modify a column in a table + */ + public function modifyColumn(string! tableName, string! schemaName, column) -> string + { + throw new Exception("Not implemented yet"); + } + + /** + * Generates SQL to delete a column from a table + */ + public function dropColumn(string! tableName, string! schemaName, string columnName) -> string + { + throw new Exception("Not implemented yet"); + } + + /** + * Generates SQL to add an index to a table + */ + public function addIndex(string! tableName, string! schemaName, index) -> string + { + throw new Exception("Not implemented yet"); + } + + /** + /** + * Generates SQL to delete an index from a table + */ + public function dropIndex(string! tableName, string! schemaName, string! indexName) -> string + { + throw new Exception("Not implemented yet"); + } + + /** + * Generates SQL to add the primary key to a table + */ + public function addPrimaryKey(string tableName, string schemaName, index) -> string + { + throw new Exception("Not implemented yet"); + } + + /** + * Generates SQL to delete primary key from a table + */ + public function dropPrimaryKey(string! tableName, string! schemaName) -> string + { + throw new Exception("Not implemented yet"); + } + + /** + * Generates SQL to add an index to a table + */ + public function addForeignKey(string! tableName, string! schemaName, reference) -> string + { + throw new Exception("Not implemented yet"); + } + + /** + * Generates SQL to delete a foreign key from a table + */ + public function dropForeignKey(string! tableName, string! schemaName, string! referenceName) -> string + { + throw new Exception("Not implemented yet"); + } + + /** + * Generates SQL to create a table in Oracle + */ + public function createTable(string! tableName, string! schemaName, array! definition) -> string + { + throw new Exception("Not implemented yet"); + } + + /** + * Generates SQL to drop a table + */ + public function dropTable(string! tableName, string! schemaName, boolean! ifExists = true) -> string + { + var table; + + if schemaName { + let table = this->escape(Text::upper(schemaName)) . "." . this->escape(Text::upper(tableName)); + } else { + let table = this->escape(Text::upper(tableName)); + } + + if ifExists { + return "DROP TABLE IF EXISTS " . table; + } else { + return "DROP TABLE " . table; + } + } + + /** + * Generates SQL to create a view + */ + public function createView(string! viewName, array! definition, string schemaName = null) -> string + { + var view, viewSql; + + if !fetch viewSql, definition["sql"] { + throw new Exception("The index 'sql' is required in the definition array"); + } + + if schemaName { + let view = this->escape(Text::upper(schemaName) . "." . Text::upper(viewName)); + } else { + let view = this->escape(Text::upper(viewName)); + } + + return "CREATE VIEW " . view . " AS " . viewSql; + } + + /** + * Generates SQL to drop a view + */ + public function dropView(string! viewName, string schemaName = null, boolean! ifExists = true) -> string + { + var view; + + if schemaName { + let view = this->escape(Text::upper(schemaName) . "." . Text::upper(viewName)); + } else { + let view = this->escape(Text::upper(viewName)); + } + + if ifExists { + return "DROP VIEW IF EXISTS " . view; + } else { + return "DROP VIEW " . view; + } + } + + /** + * Generates SQL checking for the existence of a schema.view + */ + public function viewExists(string! viewName, string schemaName = null) -> string + { + if schemaName != "" { + return "SELECT CASE WHEN COUNT(*) > 0 THEN 1 ELSE 0 END RET FROM ALL_VIEWS WHERE VIEW_NAME='" . Text::upper(viewName) . "' AND OWNER='" . Text::upper(schemaName) . "'"; + } else { + return "SELECT CASE WHEN COUNT(*) > 0 THEN 1 ELSE 0 END RET FROM ALL_VIEWS WHERE VIEW_NAME='" . Text::upper(viewName) . "'"; + } + } + + /** + * Generates the SQL to list all views of a schema or user + */ + public function listViews(string schemaName = null) -> string + { + if schemaName != "" { + return "SELECT VIEW_NAME FROM ALL_VIEWS WHERE OWNER='" . Text::upper(schemaName) . "' ORDER BY VIEW_NAME"; + } else { + return "SELECT VIEW_NAME FROM ALL_VIEWS VIEW_NAME"; + } + } + + /** + * Generates SQL checking for the existence of a schema.table + * + * + * echo $dialect->tableExists("posts", "blog"); + * echo $dialect->tableExists("posts"); + * + */ + public function tableExists(string! tableName, string schemaName = null) -> string + { + if schemaName != "" { + return "SELECT CASE WHEN COUNT(*) > 0 THEN 1 ELSE 0 END RET FROM ALL_TABLES WHERE TABLE_NAME='" . Text::upper(tableName) . "' AND OWNER = '" . Text::upper(schemaName) . "'"; + } else { + return "SELECT CASE WHEN COUNT(*) > 0 THEN 1 ELSE 0 END RET FROM ALL_TABLES WHERE TABLE_NAME='" . Text::upper(tableName) . "'"; + } + } + + /** + * Generates SQL describing a table + * + * + * print_r($dialect->describeColumns("posts")); + * + */ + public function describeColumns(string! table, string schema = null) -> string + { + if schema != "" { + return "SELECT TC.COLUMN_NAME, TC.DATA_TYPE, TC.DATA_LENGTH, TC.DATA_PRECISION, TC.DATA_SCALE, TC.NULLABLE, C.CONSTRAINT_TYPE, TC.DATA_DEFAULT, CC.POSITION FROM ALL_TAB_COLUMNS TC LEFT JOIN (ALL_CONS_COLUMNS CC JOIN ALL_CONSTRAINTS C ON (CC.CONSTRAINT_NAME = C.CONSTRAINT_NAME AND CC.TABLE_NAME = C.TABLE_NAME AND CC.OWNER = C.OWNER AND C.CONSTRAINT_TYPE = 'P')) ON TC.TABLE_NAME = CC.TABLE_NAME AND TC.COLUMN_NAME = CC.COLUMN_NAME WHERE TC.TABLE_NAME = '" . Text::upper(table) . "' AND TC.OWNER = '" . Text::upper(schema) . "' ORDER BY TC.COLUMN_ID"; + } else { + return "SELECT TC.COLUMN_NAME, TC.DATA_TYPE, TC.DATA_LENGTH, TC.DATA_PRECISION, TC.DATA_SCALE, TC.NULLABLE, C.CONSTRAINT_TYPE, TC.DATA_DEFAULT, CC.POSITION FROM ALL_TAB_COLUMNS TC LEFT JOIN (ALL_CONS_COLUMNS CC JOIN ALL_CONSTRAINTS C ON (CC.CONSTRAINT_NAME = C.CONSTRAINT_NAME AND CC.TABLE_NAME = C.TABLE_NAME AND CC.OWNER = C.OWNER AND C.CONSTRAINT_TYPE = 'P')) ON TC.TABLE_NAME = CC.TABLE_NAME AND TC.COLUMN_NAME = CC.COLUMN_NAME WHERE TC.TABLE_NAME = '" . Text::upper(table) . "' ORDER BY TC.COLUMN_ID"; + } + } + + /** + * List all tables in database + * + * + * print_r($dialect->listTables("blog")) + * + */ + public function listTables(string schemaName = null) -> string + { + if schemaName != "" { + return "SELECT TABLE_NAME, OWNER FROM ALL_TABLES WHERE OWNER='" . Text::upper(schemaName) . "' ORDER BY OWNER, TABLE_NAME"; + } else { + return "SELECT TABLE_NAME, OWNER FROM ALL_TABLES ORDER BY OWNER, TABLE_NAME"; + } + } + + /** + * Generates SQL to query indexes on a table + */ + public function describeIndexes(string! table, string schema = null) -> string + { + if schema != "" { + return "SELECT I.TABLE_NAME, 0 AS C0, I.INDEX_NAME, IC.COLUMN_POSITION, IC.COLUMN_NAME FROM ALL_INDEXES I JOIN ALL_IND_COLUMNS IC ON I.INDEX_NAME = IC.INDEX_NAME WHERE I.TABLE_NAME = '" . Text::upper(table) . "' AND IC.INDEX_OWNER = '" . Text::upper(schema) . "'"; + } else { + return "SELECT I.TABLE_NAME, 0 AS C0, I.INDEX_NAME, IC.COLUMN_POSITION, IC.COLUMN_NAME FROM ALL_INDEXES I JOIN ALL_IND_COLUMNS IC ON I.INDEX_NAME = IC.INDEX_NAME WHERE I.TABLE_NAME = '" . Text::upper(table) ."'"; + } + } + + /** + * Generates SQL to query foreign keys on a table + */ + public function describeReferences(string! table, string schema = null) -> string + { + var sql; + let sql = "SELECT AC.TABLE_NAME, CC.COLUMN_NAME, AC.CONSTRAINT_NAME, AC.R_OWNER, RCC.TABLE_NAME R_TABLE_NAME, RCC.COLUMN_NAME R_COLUMN_NAME FROM ALL_CONSTRAINTS AC JOIN ALL_CONS_COLUMNS CC ON AC.CONSTRAINT_NAME = CC.CONSTRAINT_NAME JOIN ALL_CONS_COLUMNS RCC ON AC.R_OWNER = RCC.OWNER AND AC.R_CONSTRAINT_NAME = RCC.CONSTRAINT_NAME WHERE AC.CONSTRAINT_TYPE='R' "; + + if schema != "" { + let sql .= "AND AC.OWNER='" . Text::upper(schema) . "' AND AC.TABLE_NAME = '" . Text::upper(table) . "'"; + } else { + let sql .= "AND AC.TABLE_NAME = '" . Text::upper(table) . "'"; + } + + return sql; + } + + /** + * Generates the SQL to describe the table creation options + */ + public function tableOptions(string! table, string schema = null) -> string + { + return ""; + } + + /** + * Checks whether the platform supports savepoints + */ + public function supportsSavepoints() -> boolean + { + return false; + } + + /** + * Checks whether the platform supports releasing savepoints. + */ + public function supportsReleaseSavepoints() -> boolean + { + return false; + } } diff --git a/phalcon/db/dialect/postgresql.zep b/phalcon/db/dialect/postgresql.zep index 8eeb462929a..4e2ec6dc653 100644 --- a/phalcon/db/dialect/postgresql.zep +++ b/phalcon/db/dialect/postgresql.zep @@ -31,9 +31,9 @@ use Phalcon\Db\DialectInterface; /** * Phalcon\Db\Dialect\Postgresql * - * Generates database specific SQL for the PostgreSQL RBDM + * Generates database specific SQL for the PostgreSQL RDBMS */ -class Postgresql extends Dialect implements DialectInterface +class Postgresql extends Dialect { protected _escapeChar = "\""; @@ -137,153 +137,88 @@ class Postgresql extends Dialect implements DialectInterface /** * Generates SQL to add a column to a table - * - * @param string tableName - * @param string schemaName - * @param Phalcon\Db\ColumnInterface column - * @return string */ - public function addColumn(tableName, schemaName, column) + public function addColumn(string! tableName, string! schemaName, column) -> string { throw new Exception("Not implemented yet"); } /** * Generates SQL to modify a column in a table - * - * @param string tableName - * @param string schemaName - * @param Phalcon\Db\ColumnInterface column - * @return string */ - public function modifyColumn(tableName, schemaName, column) + public function modifyColumn(string! tableName, string! schemaName, column) -> string { throw new Exception("Not implemented yet"); } /** * Generates SQL to delete a column from a table - * - * @param string tableName - * @param string schemaName - * @param string columnName - * @return string */ - public function dropColumn(tableName, schemaName, columnName) + public function dropColumn(string! tableName, string! schemaName, string! columnName) -> string { throw new Exception("Not implemented yet"); } /** * Generates SQL to add an index to a table - * - * @param string tableName - * @param string schemaName - * @param Phalcon\Db\IndexInterface index - * @return string */ - public function addIndex(tableName, schemaName, index) + public function addIndex(string! tableName, string! schemaName, index) -> string { throw new Exception("Not implemented yet"); } /** * Generates SQL to delete an index from a table - * - * @param string tableName - * @param string schemaName - * @param string indexName - * @return string */ - public function dropIndex(tableName, schemaName, indexName) + public function dropIndex(string! tableName, string! schemaName, string! indexName) -> string { throw new Exception("Not implemented yet"); } /** * Generates SQL to add the primary key to a table - * - * @param string tableName - * @param string schemaName - * @param Phalcon\Db\IndexInterface index - * @return string */ - public function addPrimaryKey(tableName, schemaName, index) + public function addPrimaryKey(string! tableName, string! schemaName, index) -> string { throw new Exception("Not implemented yet"); } /** * Generates SQL to delete primary key from a table - * - * @param string tableName - * @param string schemaName - * @return string */ - public function dropPrimaryKey(tableName, schemaName) + public function dropPrimaryKey(string! tableName, string! schemaName) -> string { throw new Exception("Not implemented yet"); } /** * Generates SQL to add an index to a table - * - * @param string tableName - * @param string schemaName - * @param Phalcon\Db\ReferenceInterface reference - * @return string */ - public function addForeignKey(tableName, schemaName, reference) + public function addForeignKey(string! tableName, string! schemaName, reference) -> string { throw new Exception("Not implemented yet"); } /** * Generates SQL to delete a foreign key from a table - * - * @param string tableName - * @param string schemaName - * @param string referenceName - * @return string */ - public function dropForeignKey(tableName, schemaName, referenceName) + public function dropForeignKey(string! tableName, string! schemaName, string! referenceName) -> string { throw new Exception("Not implemented yet"); } /** - * Generates SQL to add the table creation options - * - * @param array definition - * @return array + * Generates SQL to create a table */ - protected function _getTableOptions(definition) - { - return []; - } - - /** - * Generates SQL to create a table in PostgreSQL - * - * @param string tableName - * @param string schemaName - * @param array definition - * @return string - */ - public function createTable(tableName, schemaName, array! definition) -> string + public function createTable(string! tableName, string! schemaName, array! definition) -> string { throw new Exception("Not implemented yet"); } /** - * Generates SQL to drop a table - * - * @param string tableName - * @param string schemaName - * @param boolean ifExists - * @return boolean + * Generates SQL to drop a view */ - public function dropTable(tableName, schemaName, ifExists = true) -> string + public function dropTable(string! tableName, string schemaName = null, boolean! ifExists = true) -> string { var table, sql; @@ -302,13 +237,8 @@ class Postgresql extends Dialect implements DialectInterface /** * Generates SQL to create a view - * - * @param string viewName - * @param array definition - * @param string schemaName - * @return string */ - public function createView(viewName, definition, schemaName) -> string + public function createView(string! viewName, array! definition, string schemaName = null) -> string { var viewSql, view; @@ -327,13 +257,8 @@ class Postgresql extends Dialect implements DialectInterface /** * Generates SQL to drop a view - * - * @param string viewName - * @param string schemaName - * @param boolean ifExists - * @return string */ - public function dropView(viewName, schemaName, ifExists = true) -> string + public function dropView(string! viewName, string schemaName = null, boolean! ifExists = true) -> string { var view, sql; @@ -355,14 +280,12 @@ class Postgresql extends Dialect implements DialectInterface /** * Generates SQL checking for the existence of a schema.table * - * echo dialect->tableExists("posts", "blog") - * echo dialect->tableExists("posts") - * - * @param string tableName - * @param string schemaName - * @return string + * + * echo $dialect->tableExists("posts", "blog"); + * echo $dialect->tableExists("posts"); + * */ - public function tableExists(tableName, schemaName = null) -> string + public function tableExists(string! tableName, string schemaName = null) -> string { if schemaName { return "SELECT CASE WHEN COUNT(*) > 0 THEN 1 ELSE 0 END FROM information_schema.tables WHERE table_schema = '" . schemaName . "' AND table_name='" . tableName . "'"; @@ -372,12 +295,8 @@ class Postgresql extends Dialect implements DialectInterface /** * Generates SQL checking for the existence of a schema.view - * - * @param string viewName - * @param string schemaName - * @return string */ - public function viewExists(viewName, schemaName = null) -> string + public function viewExists(string! viewName, string schemaName = null) -> string { if schemaName { return "SELECT CASE WHEN COUNT(*) > 0 THEN 1 ELSE 0 END FROM pg_views WHERE viewname='" . viewName . "' AND schemaname='" . schemaName . "'"; @@ -386,15 +305,13 @@ class Postgresql extends Dialect implements DialectInterface } /** - * Generates a SQL describing a table + * Generates SQL describing a table * - * print_r(dialect->describeColumns("posts") ?> - * - * @param string table - * @param string schema - * @return string + * + * print_r($dialect->describeColumns("posts")); + * */ - public function describeColumns(table, schema = null) -> string + public function describeColumns(string! table, string schema = null) -> string { if schema { return "SELECT DISTINCT c.column_name AS Field, c.data_type AS Type, c.character_maximum_length AS Size, c.numeric_precision AS NumericSize, c.numeric_scale AS NumericScale, c.is_nullable AS Null, CASE WHEN pkc.column_name NOTNULL THEN 'PRI' ELSE '' END AS Key, CASE WHEN c.data_type LIKE '%int%' AND c.column_default LIKE '%nextval%' THEN 'auto_increment' ELSE '' END AS Extra, c.ordinal_position AS Position, c.column_default FROM information_schema.columns c LEFT JOIN ( SELECT kcu.column_name, kcu.table_name, kcu.table_schema FROM information_schema.table_constraints tc INNER JOIN information_schema.key_column_usage kcu on (kcu.constraint_name = tc.constraint_name and kcu.table_name=tc.table_name and kcu.table_schema=tc.table_schema) WHERE tc.constraint_type='PRIMARY KEY') pkc ON (c.column_name=pkc.column_name AND c.table_schema = pkc.table_schema AND c.table_name=pkc.table_name) WHERE c.table_schema='" . schema . "' AND c.table_name='" . table . "' ORDER BY c.ordinal_position"; @@ -405,13 +322,11 @@ class Postgresql extends Dialect implements DialectInterface /** * List all tables in database * - * - * print_r(dialect->listTables("blog")) ?> - * - * - * @param string schemaName + * + * print_r($dialect->listTables("blog")) + * */ - public function listTables(schemaName = null) -> string + public function listTables(string schemaName = null) -> string { if schemaName { return "SELECT table_name FROM information_schema.tables WHERE table_schema = '" . schemaName . "' ORDER BY table_name"; @@ -435,24 +350,16 @@ class Postgresql extends Dialect implements DialectInterface /** * Generates SQL to query indexes on a table - * - * @param string table - * @param string schema - * @return string */ - public function describeIndexes(table, schema = null) -> string + public function describeIndexes(string! table, string schema = null) -> string { return "SELECT 0 as c0, t.relname as table_name, i.relname as key_name, 3 as c3, a.attname as column_name FROM pg_class t, pg_class i, pg_index ix, pg_attribute a WHERE t.oid = ix.indrelid AND i.oid = ix.indexrelid AND a.attrelid = t.oid AND a.attnum = ANY(ix.indkey) AND t.relkind = 'r' AND t.relname = '" . table . "' ORDER BY t.relname, i.relname;"; } /** * Generates SQL to query foreign keys on a table - * - * @param string table - * @param string schema - * @return string */ - public function describeReferences(table, schema = null) -> string + public function describeReferences(string! table, string schema = null) -> string { var sql = "SELECT tc.table_name as TABLE_NAME, kcu.column_name as COLUMN_NAME, tc.constraint_name as CONSTRAINT_NAME, tc.table_catalog as REFERENCED_TABLE_SCHEMA, ccu.table_name AS REFERENCED_TABLE_NAME, ccu.column_name AS REFERENCED_COLUMN_NAME FROM information_schema.table_constraints AS tc JOIN information_schema.key_column_usage AS kcu ON tc.constraint_name = kcu.constraint_name JOIN information_schema.constraint_column_usage AS ccu ON ccu.constraint_name = tc.constraint_name WHERE constraint_type = 'FOREIGN KEY' AND "; if schema { @@ -465,12 +372,8 @@ class Postgresql extends Dialect implements DialectInterface /** * Generates the SQL to describe the table creation options - * - * @param string table - * @param string schema - * @return string */ - public function tableOptions(table, schema = null) -> string + public function tableOptions(string! table, string schema = null) -> string { return ""; } diff --git a/phalcon/db/dialect/sqlite.zep b/phalcon/db/dialect/sqlite.zep index 3906cb23b1b..bb7d8b0bf1a 100644 --- a/phalcon/db/dialect/sqlite.zep +++ b/phalcon/db/dialect/sqlite.zep @@ -32,9 +32,9 @@ use Phalcon\Db\ReferenceInterface; /** * Phalcon\Db\Dialect\Sqlite * - * Generates database specific SQL for the Sqlite RBDM + * Generates database specific SQL for the Sqlite RDBMS */ -class Sqlite extends Dialect implements DialectInterface +class Sqlite extends Dialect { protected _escapeChar = "\""; @@ -172,7 +172,7 @@ class Sqlite extends Dialect implements DialectInterface /** * Generates SQL to delete a column from a table */ - public function dropColumn(string! tableName, string! schemaName, string columnName) -> string + public function dropColumn(string! tableName, string! schemaName, string! columnName) -> string { throw new Exception("Dropping DB column is not supported by SQLite"); } @@ -219,7 +219,7 @@ class Sqlite extends Dialect implements DialectInterface /** * Generates SQL to add the primary key to a table */ - public function addPrimaryKey(string tableName, string schemaName, index) -> string + public function addPrimaryKey(string! tableName, string! schemaName, index) -> string { throw new Exception("Adding a primary key after table has been created is not supported by SQLite"); } @@ -242,30 +242,14 @@ class Sqlite extends Dialect implements DialectInterface /** * Generates SQL to delete a foreign key from a table - * - * @param string tableName - * @param string schemaName - * @param string referenceName - * @return string */ - public function dropForeignKey(string! tableName, string! schemaName, referenceName) -> string + public function dropForeignKey(string! tableName, string! schemaName, string! referenceName) -> string { throw new Exception("Dropping a foreign key constraint is not supported by SQLite"); } /** - * Generates SQL to add the table creation options - * - * @param array definition - * @return array - */ - protected function _getTableOptions(definition) -> string - { - return ""; - } - - /** - * Generates SQL to create a table in MySQL + * Generates SQL to create a table */ public function createTable(string! tableName, string! schemaName, array! definition) -> string { @@ -273,14 +257,9 @@ class Sqlite extends Dialect implements DialectInterface } /** - * Generates SQL to drop a table - * - * @param string tableName - * @param string schemaName - * @param boolean ifExists - * @return string + * Generates SQL to drop a view */ - public function dropTable(string! tableName, string! schemaName, ifExists = true) -> string + public function dropTable(string! tableName, string schemaName = null, boolean! ifExists = true) -> string { var sql, table; @@ -301,13 +280,8 @@ class Sqlite extends Dialect implements DialectInterface /** * Generates SQL to create a view - * - * @param string viewName - * @param array definition - * @param string schemaName - * @return string */ - public function createView(string! viewName, definition, string! schemaName) -> string + public function createView(string! viewName, array! definition, string schemaName = null) -> string { var view, viewSql; @@ -327,7 +301,7 @@ class Sqlite extends Dialect implements DialectInterface /** * Generates SQL to drop a view */ - public function dropView(string! viewName, string! schemaName, boolean ifExists = true) -> string + public function dropView(string! viewName, string schemaName = null, boolean! ifExists = true) -> string { var sql, view; @@ -350,27 +324,19 @@ class Sqlite extends Dialect implements DialectInterface * Generates SQL checking for the existence of a schema.table * * - * echo $dialect->tableExists("posts", "blog"); - * echo $dialect->tableExists("posts"); + * echo $dialect->tableExists("posts", "blog"); + * echo $dialect->tableExists("posts"); * - * - * @param string tableName - * @param string schemaName - * @return string */ - public function tableExists(string! tableName, schemaName = null) -> string + public function tableExists(string! tableName, string schemaName = null) -> string { return "SELECT CASE WHEN COUNT(*) > 0 THEN 1 ELSE 0 END FROM sqlite_master WHERE type='table' AND tbl_name='" . tableName . "'"; } /** * Generates SQL checking for the existence of a schema.view - * - * @param string viewName - * @param string schemaName - * @return string */ - public function viewExists(string! viewName, schemaName = null) -> string + public function viewExists(string! viewName, string schemaName = null) -> string { return "SELECT CASE WHEN COUNT(*) > 0 THEN 1 ELSE 0 END FROM sqlite_master WHERE type='view' AND tbl_name='" . viewName . "'"; } @@ -378,15 +344,11 @@ class Sqlite extends Dialect implements DialectInterface /** * Generates SQL describing a table * - * - * print_r($dialect->describeColumns("posts")); - * - * - * @param string table - * @param string schema - * @return string + * + * print_r($dialect->describeColumns("posts")); + * */ - public function describeColumns(string! table, schema = null) -> string + public function describeColumns(string! table, string schema = null) -> string { return "PRAGMA table_info('" . table . "')"; } @@ -394,11 +356,11 @@ class Sqlite extends Dialect implements DialectInterface /** * List all tables in database * - * - * print_r($dialect->listTables("blog")) - * + * + * print_r($dialect->listTables("blog")) + * */ - public function listTables(string! schemaName = null) -> string + public function listTables(string schemaName = null) -> string { return "SELECT tbl_name FROM sqlite_master WHERE type = 'table' ORDER BY tbl_name"; } @@ -413,12 +375,8 @@ class Sqlite extends Dialect implements DialectInterface /** * Generates SQL to query indexes on a table - * - * @param string table - * @param string schema - * @return string */ - public function describeIndexes(string! table, schema = null) -> string + public function describeIndexes(string! table, string schema = null) -> string { return "PRAGMA index_list('" . table . "')"; } @@ -433,24 +391,16 @@ class Sqlite extends Dialect implements DialectInterface /** * Generates SQL to query foreign keys on a table - * - * @param string table - * @param string schema - * @return string */ - public function describeReferences(string! table, schema = null) -> string + public function describeReferences(string! table, string schema = null) -> string { return "PRAGMA foreign_key_list('" . table . "')"; } /** * Generates the SQL to describe the table creation options - * - * @param string table - * @param string schema - * @return string */ - public function tableOptions(string! table, schema = null) -> string + public function tableOptions(string! table, string schema = null) -> string { return ""; } diff --git a/phalcon/db/dialectinterface.zep b/phalcon/db/dialectinterface.zep index 066ad4b1378..be57ffa8cdf 100644 --- a/phalcon/db/dialectinterface.zep +++ b/phalcon/db/dialectinterface.zep @@ -19,6 +19,12 @@ namespace Phalcon\Db; + +use Phalcon\Db\ColumnInterface; +use Phalcon\Db\ReferenceInterface; +use Phalcon\Db\IndexInterface; + + /** * Phalcon\Db\DialectInterface * @@ -29,246 +35,157 @@ interface DialectInterface /** * Generates the SQL for LIMIT clause - * - * @param string sqlQuery - * @param int number - * @return string */ - public function limit(sqlQuery, number); + public function limit(string! sqlQuery, var number) -> string; /** * Returns a SQL modified with a FOR UPDATE clause - * - * @param string sqlQuery - * @return string */ - public function forUpdate(sqlQuery); + public function forUpdate(string! sqlQuery) -> string; /** * Returns a SQL modified with a LOCK IN SHARE MODE clause - * - * @param string sqlQuery - * @return string */ - public function sharedLock(sqlQuery); + public function sharedLock(string! sqlQuery) -> string; /** * Builds a SELECT statement - * - * @param array definition - * @return string */ - public function select(array! definition); + public function select(array! definition) -> string; /** * Gets a list of columns - * - * @param array columnList - * @return string */ - public function getColumnList(array! columnList); + public function getColumnList(array! columnList) -> string; /** - * Gets the column name in MySQL + * Gets the column name in RDBMS */ - public function getColumnDefinition(<\Phalcon\Db\ColumnInterface> column); + public function getColumnDefinition( column) -> string; /** * Generates SQL to add a column to a table - * - * @param string tableName - * @param string schemaName - * @param Phalcon\Db\ColumnInterface column - * @return string */ - public function addColumn(tableName, schemaName, <\Phalcon\Db\ColumnInterface> column); + public function addColumn(string! tableName, string! schemaName, column) -> string; /** * Generates SQL to modify a column in a table - * - * @param string tableName - * @param string schemaName - * @param Phalcon\Db\ColumnInterface column - * @return string */ - public function modifyColumn(tableName, schemaName, <\Phalcon\Db\ColumnInterface> column); + public function modifyColumn(string! tableName, string! schemaName, column) -> string; + /** * Generates SQL to delete a column from a table - * - * @param string tableName - * @param string schemaName - * @param string columnName - * @return string */ - public function dropColumn(tableName, schemaName, columnName); + public function dropColumn(string! tableName, string! schemaName, string! columnName) -> string; /** * Generates SQL to add an index to a table - * - * @param string tableName - * @param string schemaName - * @param Phalcon\Db\IndexInterface index - * @return string */ - public function addIndex(tableName, schemaName, <\Phalcon\Db\IndexInterface> index); + public function addIndex(string! tableName, string! schemaName, index) -> string; /** * Generates SQL to delete an index from a table - * - * @param string tableName - * @param string schemaName - * @param string indexName - * @return string */ - public function dropIndex(tableName, schemaName, indexName); + public function dropIndex(string! tableName, string! schemaName, string! indexName) -> string; /** * Generates SQL to add the primary key to a table - * - * @param string tableName - * @param string schemaName - * @param Phalcon\Db\IndexInterface index - * @return string */ - public function addPrimaryKey(tableName, schemaName, <\Phalcon\Db\IndexInterface> index); + public function addPrimaryKey(string! tableName, string! schemaName, index) -> string; /** * Generates SQL to delete primary key from a table - * - * @param string tableName - * @param string schemaName - * @return string */ - public function dropPrimaryKey(tableName, schemaName); + public function dropPrimaryKey(string! tableName, string! schemaName) -> string; /** * Generates SQL to add an index to a table - * - * @param string tableName - * @param string schemaName - * @param Phalcon\Db\ReferenceInterface reference - * @return string */ - public function addForeignKey(tableName, schemaName, <\Phalcon\Db\ReferenceInterface> reference); + public function addForeignKey(string! tableName, string! schemaName, reference) -> string; /** * Generates SQL to delete a foreign key from a table - * - * @param string tableName - * @param string schemaName - * @param string referenceName - * @return string */ - public function dropForeignKey(tableName, schemaName, referenceName); + public function dropForeignKey(string! tableName, string! schemaName, string! referenceName) -> string; /** * Generates SQL to create a table - * - * @param string tableName - * @param string schemaName - * @param array definition - * @return string */ - public function createTable(tableName, schemaName, array! definition); + public function createTable(string! tableName, string! schemaName, array! definition) -> string; + + /** + * Generates SQL to create a view + */ + public function createView(string! viewName, array! definition, string schemaName = null) -> string; /** * Generates SQL to drop a table - * - * @param string tableName - * @param string schemaName - * @return string */ - public function dropTable(tableName, schemaName); + public function dropTable(string! tableName, string! schemaName) -> string; + + /** + * Generates SQL to drop a view + */ + public function dropView(string! viewName, string schemaName = null, boolean! ifExists = true) -> string; /** * Generates SQL checking for the existence of a schema.table - * - * @param string tableName - * @param string schemaName - * @return string */ - public function tableExists(tableName, schemaName = null); + public function tableExists(string! tableName, string schemaName = null) -> string; + + /** + * Generates SQL checking for the existence of a schema.view + */ + public function viewExists(string! viewName, string schemaName = null) -> string; /** * Generates SQL to describe a table - * - * @param string table - * @param string schema - * @return string */ - public function describeColumns(table, schema = null); + public function describeColumns(string! table, string schema = null) -> string; /** * List all tables in database - * - * @param string schemaName - * @return array */ - public function listTables(schemaName = null); + public function listTables(string schemaName = null) -> string; /** * Generates SQL to query indexes on a table - * - * @param string table - * @param string schema - * @return string */ - public function describeIndexes(table, schema = null); + public function describeIndexes(string! table, string schema = null) -> string; /** * Generates SQL to query foreign keys on a table - * - * @param string table - * @param string schema - * @return string */ - public function describeReferences(table, schema = null); + public function describeReferences(string! table, string schema = null) -> string; /** * Generates the SQL to describe the table creation options - * - * @param string table - * @param string schema - * @return string */ - public function tableOptions(table, schema = null); + public function tableOptions(string! table, string schema = null) -> string; /** * Checks whether the platform supports savepoints - * - * @return boolean */ - public function supportsSavepoints(); + public function supportsSavepoints() -> boolean; /** * Checks whether the platform supports releasing savepoints. - * - * @return boolean */ - public function supportsReleaseSavepoints(); + public function supportsReleaseSavepoints() -> boolean; /** * Generate SQL to create a new savepoint - * - * @param string name - * @return string */ - public function createSavepoint(name); + public function createSavepoint(string! name) -> string; /** * Generate SQL to release a savepoint - * - * @param string name - * @return string */ - public function releaseSavepoint(name); + public function releaseSavepoint(string! name) -> string; /** * Generate SQL to rollback a savepoint - * - * @param string name - * @return string */ - public function rollbackSavepoint(name); + public function rollbackSavepoint(string! name) -> string; }