diff -E -b -w -B -r postgresql-8.0.0beta3-ori/src/backend/tcop/postgres.c postgresql-8.0.0beta3_WH/src/backend/tcop/postgres.c
63a64,68
> 
> 
> #include "nodes/pg_list.h"
> 
> 
446a454,792
> 
> 
> 
> 
> #ifdef SUPPORT_EXTENDED_JOIN_SYNTAX
> 
> /*
>  * support something IMHO "non_logical" as the following ..
>  *
>  * select t1.c1, t2.c2, t3.c3
>  * from tab1 t1 left outer join tab2 t2 on t1.i1 = t2.i2,
>  *	tab1 left outer join tab3 t3 on t1.i1 = t3.i3
>  *
>  * .. is converted to what it shall really mean, ..
>  *
>  * select t1.c1, t2.c2, t3.c3
>  * from tab1 t1 left outer join tab2 t2 on t1.i1 = t2.i2
>  *	left outer join tab3 t3 on t1.i1 = t3.i3
>  *
>  */
> 
> #define TMP_IS_LARG 0 
> #define TMP_IS_RARG 1 
> 
> // sizof(RangeVar) is 28 (7*4) so we can cast it to this kind af struct
> typedef struct tmp_RangeVar {
>     Node *jfrom;	// (type)
>     JoinExpr *jto;	// (catalogname)
>     char *aliasname;	// (schemaname)
>     char *relname;	// (relname)
>     char jfrom_index;	// index of jfrom (ancestor) in from clause [0..128]
>     char jto_lr;	// determine if jto was larg (= 0) or rarg = 1
> //} __attribute__((__packed__)) tmp_RangeVar;
> } tmp_RangeVar;
> 
> 
> /*
>  * should return 2 for a complete aliased join qualifier
>  */
> int count_qual_strings(Node *n) {
>     int refs = 0;
>     ColumnRef *c;
>     List *f;
>     ListCell *f_item;
>     Value *v;
>     if (IsA(n, ColumnRef)) {
>         c = (ColumnRef *)n;
> 	f = c->fields;
> 	foreach(f_item, f) {
>     	    n = (Node *)lfirst(f_item);
>     	    if (n->type == T_String) {
> 	        v = (Value *)n;
> 	        if (strlen(v->val.str) > 0) {
> 		    refs++;
> 		}
> 	    }
> 	}
>     }
>     return refs;
> }
> 
> 
> /*
>  * to keep it simple - only if both sides of qualifiers are aliased go further ..
>  * returns 0 for success, 1 for not or partially aliased
>  */
> int is_fully_aliased_qualifier(Node *q) {
>     A_Expr *a;
>     int refs = 0;
> 
>     if (
> 	(q != (Node *)0)
> //     && (!IsA(q, List))		// if q exists and is no USING clause .. {ON A_Expr}
>      && (IsA(q, A_Expr))
>      ) {
>         a = (A_Expr *)q;
>         if (a->lexpr != (Node *)0) refs += count_qual_strings(a->lexpr);
>         if (a->rexpr != (Node *)0) refs += count_qual_strings(a->rexpr);
>     }
>     if (refs > 3) return 0; else return 1;
> }
> 
> 
> /*
>  * Step 1
>  * find recursively an unaliased table in a join expression
>  * where it should have been aliased (for a stand alone join)
>  * use the RangeVar struct for temporary storage of Node* (larg or rarg), relname
>  */
> RangeVar *find_incomplete_JoinExpr(JoinExpr *j);
> 
> RangeVar *find_incomplete_one_side(Node *n, JoinExpr *z, char lr) {
>     JoinExpr *j;
>     RangeVar *r;
>     tmp_RangeVar *t;
>     if (IsA(n, JoinExpr)) {
> 	j = (JoinExpr *)n;
> 	r = find_incomplete_JoinExpr(j);
>     } else if (IsA(n, RangeVar)) {
> 	r = (RangeVar *)n;
> 	if (r->alias == (Alias *)0) {	// if not aliased ..
> 	    t = (tmp_RangeVar *)n;
> 	    t->jto_lr = lr;		// remember which of larg or rarg
> 	    t->jto = z;			// remember where we once belonged ..
> 	    return r;			// use this now useless RangeVar as temporary storage
> 	}
>     }
>     return (RangeVar *)0;
> }
> 
> 
> RangeVar *find_incomplete_JoinExpr(JoinExpr *j) {
>     RangeVar *r = (RangeVar *)0;
>     if (is_fully_aliased_qualifier(j->quals) == 0) {
> 	r = find_incomplete_one_side(j->larg, j, 0);
> 	if (r != (RangeVar *)0) return r;
> 	r = find_incomplete_one_side(j->rarg, j, 1);
>     }
>     return r;
> }
> 
> 
> /*
>  * Step 2
>  * find recursively an aliased table in a join expression
>  * where z->relname appeares to be used and aliased as larg or rarg
>  */
> RangeVar *find_appropriate_JoinExpr(JoinExpr *j, RangeVar *z);
> 
> RangeVar *find_appropriate_one_side(Node *n, RangeVar *z) {
>     RangeVar *r = (RangeVar *)0;
>     JoinExpr *je;
>     Alias *a;
>     tmp_RangeVar *t;
>     if (IsA(n, JoinExpr)) {
> 	je = (JoinExpr *)n;
> 	r = find_appropriate_JoinExpr(je, z);
> 	return r;
>     } else if (IsA(n, RangeVar)) {
> 	r = (RangeVar *)n;
> 	if (
> 	    (r->alias != (Alias *)0)
> 	 && (strcmp(z->relname, r->relname) == 0)
> 	 ) {
> 	    a = (Alias *)r->alias;
> 	    t = (tmp_RangeVar *)z;
> 	    t->aliasname = strdup(a->aliasname);	// use catalogname as aliasname, don't forget to free() or use pstrdup()
> 	    return z;
> 	} else {
> 	    return (RangeVar *)0;
> 	}
>     }
>     return r;
> }
> 
> 
> RangeVar *find_appropriate_JoinExpr(JoinExpr *j, RangeVar *z) {
>     RangeVar *r;
>     // .. here evaluate j->quals ..
>     r = find_appropriate_one_side(j->larg, z);
>     if (r != (RangeVar *)0) return r;			// return 1st thing !=0 (found)
>     r = find_appropriate_one_side(j->rarg, z);
>     return r;
> }
> 
> 
> /*
>  * pg_list.h
>  * (for Step 3)
>  */
> ListCell *listcell_remove(List *l, ListCell *l_item) {
>     ListCell *l_run;
>     l_run = list_head(l);
>     if (l_run == l_item) {
> 	l->head = l_item->next;
> 	return l_item;
>     }
>     while (l_run != NULL) {
> 	if (l_run->next == l_item) {
> 	    l_run->next = l_item->next; 	// e.g. = NULL 
> 	    break;
> 	}
> 	l_run = l_run->next;
>     }
>     return l_item;
> }
> 
> 
> 
> void correct_selectstmt(SelectStmt *st);
> 
> void correct_rangesub(RangeSubselect *u) {
>     Node *n;
>     n = (Node *)u->subquery;
>     if (n != (Node *)0) {
> //	elog(NOTICE, "u->subquery is type %d", n->type);
> 	if (IsA(n, SelectStmt)) {
> 	    correct_selectstmt((SelectStmt *)n);	
>         }
>     } else {
> //	elog(NOTICE, "u->subquery is NULL (ERROR)");
>     }
> }
> 
> 
> 
> void correct_selectstmt(SelectStmt *st) {
> 
>     RangeVar *r = 0;	// handle for information storage
>     Node *n;
>     List *fc;
>     ListCell *fc_item;
>     tmp_RangeVar *t;
>     JoinExpr *j;
>     int fc_index1, fc_index2, found;
> 
>     if (st->fromClause) {	// may be there is none ..
> 	fc = st->fromClause;	// List
> 	if (fc->length > 0) {
> 
> 	    // loop through List fromClause searching for subselect statements (make it recursive) ..
> 	    foreach(fc_item, fc) {
> 		n = (Node *)lfirst(fc_item);
> //		elog(NOTICE, "correct_selectstmt(), n is type %d (333=T_JoinExpr/810=RangeSubselect)", n->type);
> 		if (IsA(n, JoinExpr)) {
> 		    j = (JoinExpr *)n;
> 		    n = (Node *)j->larg;
> 		    if (IsA(n, RangeSubselect)) {
> 			correct_rangesub((RangeSubselect *)n);
> 		    }
> 		    n = (Node *)j->rarg;
> 		    if (IsA(n, RangeSubselect)) {
> 			correct_rangesub((RangeSubselect *)n);
> 		    }
> 		} else if (IsA(n, RangeSubselect)) {
> 		    correct_rangesub((RangeSubselect *)n);
> 		}
> 	    }
> 
> 	    if (fc->length < 2) return;	// nothing to search further if fromClause comprises 1 item only ..
> 
> 	    goto start_loop;		// i love these unavoidable goto's - they are not ugly at all!
> 
> 	    do {
> 
> 		// loop through List fromClause 2nd time, now trying to find the Joinexpression containing the same
> 		//  but completely referenced table
> 		fc_index2 = 0;
>     		foreach(fc_item, fc) {
> 		    if (fc_index1 != fc_index2) {	// complete and incomplete syntax cannot reside in same fc_item
> 			n = (Node *)lfirst(fc_item);
> 			// RangeVar would be possible here too, but foolish syntax - not supported ..
> 			if (IsA(n, JoinExpr)) {
> 		    	    if ((r = find_appropriate_JoinExpr((JoinExpr *)n, r)) != (RangeVar *)0) {
> 				t = (tmp_RangeVar *)r;
> 			        t->jfrom = n;
> 			        t->jfrom_index = fc_index2;	// remember index of element to remove
> 			        break;
> 		    	    }
> 			}
> 		    }
> 		    fc_index2++;
>     		}
> 
> 		if (r != (RangeVar *)0) {	// if we found anything as described before ..
> 		    t = (tmp_RangeVar *)r;
> 		    // remove JoinExpr item from fromclause
> 	    	    fc_index1 = 0;
> 		    foreach(fc_item, fc) {
> 	    		n = (Node *)lfirst(fc_item);
> 			if (fc_index1 == t->jfrom_index) {
> 			// if (r->jfrom == (JoinExpr *) lfirst(fc_item))
> 		    	    fc_item = listcell_remove(fc, fc_item);
> 			    fc->length--;	// one element shorter now
> 		    	    break;
> 			}
> 			fc_index1++;
> 		    }
> 		    // connect join to location of former RangeVar
> 	    	    if (t->jto_lr == 0) {
> 			t->jto->larg = fc_item->data.ptr_value;
> 		    } else if (t->jto_lr == 1) {
> 		        t->jto->rarg = fc_item->data.ptr_value;
> 		    }
> 		    free(t->aliasname); 	// if there is a RangeVar struct != 0:  we have strdup()'ed this one
> 		} // else syntax error
> 
> start_loop:
> 		found = 0;
> 	        fc_index1 = 0;
> 	        // loop through List fromClause trying to find an incomplete aliased reference
> 	        foreach(fc_item, fc) {
> 		    n = (Node *)lfirst(fc_item);
> 		    // RangeVar would be possible here too, but foolish syntax - not supported ..
> 		    if (IsA(n, JoinExpr)) {
> 			if ((r = find_incomplete_JoinExpr((JoinExpr *)n)) != (RangeVar *)0) {
> 		    	    found = 1;
> 			    break;
> 			}
> 		    }
> 		    fc_index1++;
> 		}
> 
> 	    } while (found);	// if nothing partially aliased - end here
> 	    // do it while there are incomplete aliased JoinExpressions in fromClause
> 	}
>     }
> }
> 
> 
> /*
>  * search for select and cursor statements
>  */
> void correct_extended_from_clause_syntax(List *raw_parse_tree_list) {
>     Node *n;
>     ListCell *parsetree_item;
>     SelectStmt *st;
>     DeclareCursorStmt *dc;
>     foreach(parsetree_item, raw_parse_tree_list) {
>         n = (Node *) lfirst(parsetree_item);
> 	// only "select statements" are of any interest here ..
>         // (our select statement must have a "from clause" or it's not what we are searching for ..)
>         if (IsA(n, DeclareCursorStmt)) {
> 	    dc = (DeclareCursorStmt *)n;
> 	    st = (SelectStmt *)dc->query;
> 	    correct_selectstmt(st);
> 	} else if (IsA(n, SelectStmt)) {
>     	    st = (SelectStmt *)n;
> 	    correct_selectstmt(st);
> 	}
>     }
>     return;
> }
> 
> #endif
> 
> 
> 
> 
460,462c806
< List *
< pg_parse_query(const char *query_string)
< {
---
> List * pg_parse_query(const char *query_string) {
467,468c812
< 		ereport(LOG,
< 				(errmsg("statement: %s", query_string)));
---
> 		ereport(LOG, (errmsg("statement: %s", query_string)));
470,471c814
< 	if (log_parser_stats)
< 		ResetUsage();
---
> 	if (log_parser_stats) ResetUsage();
474a818,823
> 
> #ifdef SUPPORT_EXTENDED_JOIN_SYNTAX
> 	// provide compatibility with an elsewhere supported feature ..
> 	correct_extended_from_clause_syntax(raw_parsetree_list);
> #endif
> 
diff -E -b -w -B -r postgresql-8.0.0beta3-ori/src/backend/utils/adt/numutils.c postgresql-8.0.0beta3_WH/src/backend/utils/adt/numutils.c
71c71,74
< 	if (*s == 0)
---
> 
> 
> 	if (*s == 0) {
> #ifndef NULLSTRING_IS_INTEGER_0
75a79,85
> #else
> 	    l = 0;
> #endif
> 	} else {
98a109
> 	}
diff -E -b -w -B -r postgresql-8.0.0beta3-ori/src/include/postgres.h postgresql-8.0.0beta3_WH/src/include/postgres.h
47a48,60
> 
> // in backend/parser/gram.y convert all "like" to "ilike"
> // for doing case insensitive processing (partially) as 
> // some apps expect
> // #define LIKE_IS_ILIKE
> 
> // in "backend/tcop/postgres.c"  support select .. from .. syntax as described there ..
> #define SUPPORT_EXTENDED_JOIN_SYNTAX
> 
> // in "backend/utils/atd/numutils.c"  count input of '' for integer field as 0
> // #define NULLSTRING_IS_INTEGER_0
> 
diff -E -b -w -B -r postgresql-8.0.0beta3-ori/src/backend/parser/parser.c postgresql-8.0.0beta3_WH/src/backend/parser/parser.c
105a106,110
> #ifdef LIKE_IS_ILIKE
> 	if (cur_token == LIKE)
> 	    cur_token = LIKE;
> #endif 
> 
