Skip to content

Commit

Permalink
Merge pull request #1122 from sjinks/issue-1115
Browse files Browse the repository at this point in the history
[NFR] Allow HAVING without GROUP BY in the query builder
  • Loading branch information
Phalcon committed Aug 20, 2013
2 parents cbe2303 + 490e504 commit 4427167
Show file tree
Hide file tree
Showing 22 changed files with 2,947 additions and 5,635 deletions.
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -472,10 +472,10 @@ unit-tests/annotations/cache/*.php
*.lo
*.loT
.libs
parser.out
lemon
build/t.dSYM/
build/install2
*~
.DS_Store
ext/.DS_Store
ext/mvc/view/engine/volt/parser.out
ext/mvc/view/engine/volt/lemon
1 change: 1 addition & 0 deletions ext/Makefile.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
%.c : %.y
2 changes: 2 additions & 0 deletions ext/config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -416,4 +416,6 @@ image/adapter/imagick.c"
)

CPPFLAGS=$old_CPPFLAGS

PHP_ADD_MAKEFILE_FRAGMENT
fi
29 changes: 25 additions & 4 deletions ext/db/dialect.c
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,12 @@ PHP_METHOD(Phalcon_Db_Dialect, getSqlExpression){

PHALCON_INIT_VAR(arguments_joined);
phalcon_fast_join_str(arguments_joined, SL(", "), sql_arguments TSRMLS_CC);
PHALCON_CONCAT_VSVS(return_value, name, "(", arguments_joined, ")");
if (phalcon_array_isset_string(expression, SS("distinct"))) {
PHALCON_CONCAT_VSVS(return_value, name, "(DISTINCT ", arguments_joined, ")");
}
else {
PHALCON_CONCAT_VSVS(return_value, name, "(", arguments_joined, ")");
}

RETURN_MM();
} else {
Expand Down Expand Up @@ -571,7 +576,7 @@ PHP_METHOD(Phalcon_Db_Dialect, getSqlTable){
*/
PHP_METHOD(Phalcon_Db_Dialect, select){

zval *definition, *escape_char = NULL, *columns, *selected_columns;
zval *definition, *escape_char = NULL, *columns, *selected_columns, *distinct;
zval *column = NULL, *column_item = NULL, *column_sql = NULL, *column_domain = NULL;
zval *column_domain_sql = NULL, *column_alias = NULL, *column_alias_sql = NULL;
zval *columns_sql = NULL, *tables, *selected_tables;
Expand Down Expand Up @@ -733,9 +738,25 @@ PHP_METHOD(Phalcon_Db_Dialect, select){
} else {
PHALCON_CPY_WRT(tables_sql, tables);
}

PHALCON_INIT_VAR(sql);
PHALCON_CONCAT_SVSV(sql, "SELECT ", columns_sql, " FROM ", tables_sql);
if (phalcon_array_isset_string_fetch(&distinct, definition, SS("definition"))) {
assert(Z_TYPE_P(distinct) == IS_LONG);
if (Z_LVAL_P(distinct) == 0) {
ZVAL_STRING(sql, "SELECT ALL ", 1);
}
else if (Z_LVAL_P(distinct) == 1) {
ZVAL_STRING(sql, "SELECT DISTINCT ", 1);
}
else {
ZVAL_STRING(sql, "SELECT ", 1);
}
}
else {
ZVAL_STRING(sql, "SELECT ", 1);
}

PHALCON_SCONCAT_VSV(sql, columns_sql, " FROM ", tables_sql);

/**
* Check for joins
Expand Down
19 changes: 16 additions & 3 deletions ext/db/dialect/oracle.c
Original file line number Diff line number Diff line change
Expand Up @@ -838,7 +838,7 @@ PHP_METHOD(Phalcon_Db_Dialect_Oracle, limit){
*/
PHP_METHOD(Phalcon_Db_Dialect_Oracle, select){

zval *definition, *escape_char = NULL, *columns, *selected_columns;
zval *definition, *escape_char = NULL, *columns, *selected_columns, *distinct;
zval *column = NULL, *column_item = NULL, *column_sql = NULL, *columns_sql = NULL;
zval *column_domain = NULL, *column_domain_sql = NULL, *column_alias = NULL;
zval *column_alias_sql = NULL, *tables, *selected_tables;
Expand Down Expand Up @@ -1003,8 +1003,21 @@ PHP_METHOD(Phalcon_Db_Dialect_Oracle, select){
PHALCON_CPY_WRT(tables_sql, tables);
}

PHALCON_INIT_VAR(sql);
PHALCON_CONCAT_SVSV(sql, "SELECT ", columns_sql, " FROM ", tables_sql);
if (phalcon_array_isset_string_fetch(&distinct, definition, SS("definition"))) {
assert(Z_TYPE_P(distinct) == IS_LONG);
if (Z_LVAL_P(distinct) == 0) {
ZVAL_STRING(sql, "SELECT ALL ", 1);
}
else if (Z_LVAL_P(distinct) == 1) {
ZVAL_STRING(sql, "SELECT DISTINCT ", 1);
}
else {
ZVAL_STRING(sql, "SELECT ", 1);
}
}
else {
ZVAL_STRING(sql, "SELECT ", 1);
}

/**
* Check for joins
Expand Down
10 changes: 5 additions & 5 deletions ext/kernel/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -305,11 +305,11 @@ int phalcon_is_iterable_ex(zval *arr, HashTable **arr_hash, HashPosition *hash_p
return 1;
}

/**
* Generates error when inherited class isn't found
*/
void phalcon_inherit_not_found(const char *class_name, const char *inherit_name) {
fprintf(stderr, "Phalcon Error: Class to extend '%s' was not found when registering class '%s'\n", class_name, inherit_name);
void phalcon_safe_zval_ptr_dtor(zval *pzval)
{
if (pzval) {
zval_ptr_dtor(&pzval);
}
}

/**
Expand Down
2 changes: 2 additions & 0 deletions ext/kernel/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ extern int phalcon_fast_count_ev(zval *array TSRMLS_DC);

/* Utils functions */
extern int phalcon_is_iterable_ex(zval *arr, HashTable **arr_hash, HashPosition *hash_position, int duplicate, int reverse);
void phalcon_safe_zval_ptr_dtor(zval *pzval);


/* Fetch Parameters */
extern int phalcon_fetch_parameters(int num_args TSRMLS_DC, int required_args, int optional_args, ...);
Expand Down
80 changes: 45 additions & 35 deletions ext/mvc/model/query.c
Original file line number Diff line number Diff line change
Expand Up @@ -512,28 +512,31 @@ PHP_METHOD(Phalcon_Mvc_Model_Query, _getCallArgument){
PHP_METHOD(Phalcon_Mvc_Model_Query, _getFunctionCall){

zval *expr, *name, *arguments, *function_args = NULL, *argument = NULL;
zval *argument_expr = NULL, *function_call = NULL;
zval *argument_expr = NULL;
HashTable *ah0;
HashPosition hp0;
zval **hd;
int distinct;

PHALCON_MM_GROW();

phalcon_fetch_params(1, 1, 0, &expr);

array_init_size(return_value, 4);

PHALCON_OBS_VAR(name);
phalcon_array_fetch_string(&name, expr, SL("name"), PH_NOISY);
if (phalcon_array_isset_string(expr, SS("arguments"))) {
if (phalcon_array_isset_string_fetch(&arguments, expr, SS("arguments"))) {

distinct = phalcon_array_isset_string(expr, SS("distinct")) ? 1 : 0;

PHALCON_OBS_VAR(arguments);
phalcon_array_fetch_string(&arguments, expr, SL("arguments"), PH_NOISY);
if (phalcon_array_isset_long(arguments, 0)) {

/**
* There are more than one argument
*/
PHALCON_INIT_VAR(function_args);
array_init(function_args);
array_init_size(function_args, zend_hash_num_elements(Z_ARRVAL_P(arguments)));

phalcon_is_iterable(arguments, &ah0, &hp0, 0, 0);

Expand All @@ -543,7 +546,7 @@ PHP_METHOD(Phalcon_Mvc_Model_Query, _getFunctionCall){

PHALCON_INIT_NVAR(argument_expr);
phalcon_call_method_p1(argument_expr, this_ptr, "_getcallargument", argument);
phalcon_array_append(&function_args, argument_expr, PH_SEPARATE);
phalcon_array_append(&function_args, argument_expr, 0);

zend_hash_move_forward_ex(ah0, &hp0);
}
Expand All @@ -560,19 +563,19 @@ PHP_METHOD(Phalcon_Mvc_Model_Query, _getFunctionCall){
phalcon_array_append(&function_args, argument_expr, PH_SEPARATE);
}

PHALCON_INIT_VAR(function_call);
array_init_size(function_call, 3);
add_assoc_stringl_ex(function_call, SS("type"), SL("functionCall"), 1);
phalcon_array_update_string(&function_call, SL("name"), &name, PH_COPY | PH_SEPARATE);
phalcon_array_update_string(&function_call, SL("arguments"), &function_args, PH_COPY | PH_SEPARATE);
add_assoc_stringl_ex(return_value, SS("type"), SL("functionCall"), 1);
phalcon_array_update_string(&return_value, SL("name"), &name, PH_COPY);
phalcon_array_update_string(&return_value, SL("arguments"), &function_args, PH_COPY);

if (distinct) {
add_assoc_bool_ex(return_value, SS("distinct"), distinct);
}
} else {
PHALCON_INIT_NVAR(function_call);
array_init_size(function_call, 2);
add_assoc_stringl_ex(function_call, SS("type"), SL("functionCall"), 1);
phalcon_array_update_string(&function_call, SL("name"), &name, PH_COPY | PH_SEPARATE);
add_assoc_stringl_ex(return_value, SS("type"), SL("functionCall"), 1);
phalcon_array_update_string(&return_value, SL("name"), &name, PH_COPY);
}

RETURN_CTOR(function_call);
PHALCON_MM_RESTORE();
}

/**
Expand Down Expand Up @@ -1230,7 +1233,7 @@ PHP_METHOD(Phalcon_Mvc_Model_Query, _getSelectColumn){
/**
* Check for columns qualified and not qualified
*/
if (PHALCON_IS_LONG(column_type, 354)) {
if (PHALCON_IS_LONG(column_type, PHQL_T_EXPR)) {

/**
* The sql_column is a scalar type returning a simple string
Expand Down Expand Up @@ -2455,7 +2458,7 @@ PHP_METHOD(Phalcon_Mvc_Model_Query, _getLimitClause) {
*/
PHP_METHOD(Phalcon_Mvc_Model_Query, _prepareSelect){

zval *ast, *select, *sql_models, *sql_tables, *sql_aliases;
zval *ast, *select, *distinct = NULL, *sql_models, *sql_tables, *sql_aliases;
zval *sql_columns, *sql_aliases_models, *sql_models_aliases;
zval *sql_aliases_models_instances, *models;
zval *models_instances, *tables, *selected_models = NULL;
Expand Down Expand Up @@ -2490,6 +2493,8 @@ PHP_METHOD(Phalcon_Mvc_Model_Query, _prepareSelect){
return;
}

phalcon_array_isset_string_fetch(&distinct, select, SS("distinct"));

/**
* sql_models are all the models that are using in the query
*/
Expand Down Expand Up @@ -2658,9 +2663,9 @@ PHP_METHOD(Phalcon_Mvc_Model_Query, _prepareSelect){
} else {
PHALCON_INIT_NVAR(complete_source);
array_init_size(complete_source, 3);
phalcon_array_append(&complete_source, source, PH_SEPARATE);
phalcon_array_append(&complete_source, source, 0);
add_next_index_null(complete_source);
phalcon_array_append(&complete_source, alias, PH_SEPARATE);
phalcon_array_append(&complete_source, alias, 0);
}

phalcon_array_update_zval(&models, model_name, &alias, PH_COPY | PH_SEPARATE);
Expand Down Expand Up @@ -2780,7 +2785,7 @@ PHP_METHOD(Phalcon_Mvc_Model_Query, _prepareSelect){
}
}
}
PHALCON_SEPARATE(position);

phalcon_increment(position);

zend_hash_move_forward_ex(ah2, &hp2);
Expand All @@ -2795,12 +2800,17 @@ PHP_METHOD(Phalcon_Mvc_Model_Query, _prepareSelect){
* sql_select is the final prepared SELECT
*/
PHALCON_INIT_VAR(sql_select);
array_init_size(sql_select, 3);
phalcon_array_update_string(&sql_select, SL("models"), &sql_models, PH_COPY | PH_SEPARATE);
phalcon_array_update_string(&sql_select, SL("tables"), &sql_tables, PH_COPY | PH_SEPARATE);
phalcon_array_update_string(&sql_select, SL("columns"), &sql_columns, PH_COPY | PH_SEPARATE);
array_init_size(sql_select, 10);

if (distinct) {
phalcon_array_update_string(&sql_select, SL("distinct"), &distinct, PH_COPY);
}

phalcon_array_update_string(&sql_select, SL("models"), &sql_models, PH_COPY);
phalcon_array_update_string(&sql_select, SL("tables"), &sql_tables, PH_COPY);
phalcon_array_update_string(&sql_select, SL("columns"), &sql_columns, PH_COPY);
if (phalcon_fast_count_ev(sql_joins TSRMLS_CC)) {
phalcon_array_update_string(&sql_select, SL("joins"), &sql_joins, PH_COPY | PH_SEPARATE);
phalcon_array_update_string(&sql_select, SL("joins"), &sql_joins, PH_COPY);
}

/**
Expand All @@ -2812,7 +2822,7 @@ PHP_METHOD(Phalcon_Mvc_Model_Query, _prepareSelect){

PHALCON_INIT_VAR(where_expr);
phalcon_call_method_p1(where_expr, this_ptr, "_getexpression", where);
phalcon_array_update_string(&sql_select, SL("where"), &where_expr, PH_COPY | PH_SEPARATE);
phalcon_array_update_string(&sql_select, SL("where"), &where_expr, PH_COPY);
}

/**
Expand All @@ -2824,7 +2834,7 @@ PHP_METHOD(Phalcon_Mvc_Model_Query, _prepareSelect){

PHALCON_INIT_VAR(sql_group);
phalcon_call_method_p1(sql_group, this_ptr, "_getgroupclause", group_by);
phalcon_array_update_string(&sql_select, SL("group"), &sql_group, PH_COPY | PH_SEPARATE);
phalcon_array_update_string(&sql_select, SL("group"), &sql_group, PH_COPY);
}

/**
Expand All @@ -2836,7 +2846,7 @@ PHP_METHOD(Phalcon_Mvc_Model_Query, _prepareSelect){

PHALCON_INIT_VAR(having_expr);
phalcon_call_method_p1(having_expr, this_ptr, "_getexpression", having);
phalcon_array_update_string(&sql_select, SL("having"), &having_expr, PH_COPY | PH_SEPARATE);
phalcon_array_update_string(&sql_select, SL("having"), &having_expr, PH_COPY);
}

/**
Expand All @@ -2848,7 +2858,7 @@ PHP_METHOD(Phalcon_Mvc_Model_Query, _prepareSelect){

PHALCON_INIT_VAR(sql_order);
phalcon_call_method_p1(sql_order, this_ptr, "_getorderclause", order);
phalcon_array_update_string(&sql_select, SL("order"), &sql_order, PH_COPY | PH_SEPARATE);
phalcon_array_update_string(&sql_select, SL("order"), &sql_order, PH_COPY);
}

/**
Expand Down Expand Up @@ -3529,22 +3539,22 @@ PHP_METHOD(Phalcon_Mvc_Model_Query, parse){

switch (phalcon_get_intval(type)) {

case 309:
case PHQL_T_SELECT:
PHALCON_INIT_NVAR(ir_phql);
phalcon_call_method(ir_phql, this_ptr, "_prepareselect");
break;

case 306:
case PHQL_T_INSERT:
PHALCON_INIT_NVAR(ir_phql);
phalcon_call_method(ir_phql, this_ptr, "_prepareinsert");
break;

case 300:
case PHQL_T_UPDATE:
PHALCON_INIT_NVAR(ir_phql);
phalcon_call_method(ir_phql, this_ptr, "_prepareupdate");
break;

case 303:
case PHQL_T_DELETE:
PHALCON_INIT_NVAR(ir_phql);
phalcon_call_method(ir_phql, this_ptr, "_preparedelete");
break;
Expand Down Expand Up @@ -3855,7 +3865,7 @@ PHP_METHOD(Phalcon_Mvc_Model_Query, _executeSelect){
phalcon_array_fetch_string(&sql_column, column, SL("column"), PH_NOISY);

/**
* Complete objects are treaded in a different way
* Complete objects are treated in a different way
*/
if (PHALCON_IS_STRING(type, "object")) {

Expand Down
18 changes: 18 additions & 0 deletions ext/mvc/model/query/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
all: scanner.c parser.c lemon

lemon: lemon.c
$(CC) -O2 "$<" -o "$@"

scanner.c: scanner.re Makefile
re2c -b -o "$@" "$<"
sed -i 's!^#line.*$$!/* & */!g' "$@"

parser.c: parser.y base.c Makefile lemon
./lemon -s -q "$<"
cat base.c >> "$@"
sed -i 's!^#line.*$$!/* & */!g' "$@"

clean:
-rm -f *.o *.lo lemon

.PHONY: clean
4 changes: 4 additions & 0 deletions ext/mvc/model/query/base.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ const phql_token_names phql_tokens[] =
{ SL("CAST"), PHQL_T_CAST },
{ SL("CONVERT"), PHQL_T_CONVERT },
{ SL("USING"), PHQL_T_USING },
{ SL("ALL"), PHQL_T_ALL },
{ NULL, 0, 0 }
};

Expand Down Expand Up @@ -458,6 +459,9 @@ int phql_internal_parse_phql(zval **result, char *phql, unsigned int phql_length
case PHQL_T_DISTINCT:
phql_(phql_parser, PHQL_DISTINCT, NULL, parser_status);
break;
case PHQL_T_ALL:
phql_(phql_parser, PHQL_ALL, NULL, parser_status);
break;
case PHQL_T_CAST:
phql_(phql_parser, PHQL_CAST, NULL, parser_status);
break;
Expand Down
Loading

0 comments on commit 4427167

Please sign in to comment.