ole32: Clarify the timestamp fields in StgProperty.
[wine] / dlls / msi / sql.y
index fbe813d..969c92c 100644 (file)
@@ -17,7 +17,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 
 #include "windef.h"
 #include "winbase.h"
 #include "query.h"
+#include "wine/list.h"
 #include "wine/debug.h"
 #include "wine/unicode.h"
 
 #define YYLEX_PARAM info
 #define YYPARSE_PARAM info
 
-extern int SQL_error(const char *str);
+static int sql_error(const char *str);
 
 WINE_DEFAULT_DEBUG_CHANNEL(msi);
 
@@ -45,24 +46,27 @@ typedef struct tag_SQL_input
     MSIDATABASE *db;
     LPCWSTR command;
     DWORD n, len;
+    UINT r;
     MSIVIEW **view;  /* view structure for the resulting query */
+    struct list *mem;
 } SQL_input;
 
-static LPWSTR SQL_getstring( struct sql_str *str );
-static INT SQL_getint( SQL_input *sql );
-static int SQL_lex( void *SQL_lval, SQL_input *info);
+static UINT SQL_getstring( void *info, const struct sql_str *strdata, LPWSTR *str );
+static INT SQL_getint( void *info );
+static int sql_lex( void *SQL_lval, SQL_input *info );
 
-static MSIVIEW *do_one_select( MSIDATABASE *db, MSIVIEW *in, 
-                               string_list *columns );
+static LPWSTR parser_add_table( void *info, LPCWSTR list, LPCWSTR table );
+static void *parser_alloc( void *info, unsigned int sz );
+static column_info *parser_alloc_column( void *info, LPCWSTR table, LPCWSTR column );
 
-static BOOL SQL_MarkPrimaryKeys( create_col_info *cols,
-                                 string_list *keys);
+static BOOL SQL_MarkPrimaryKeys( column_info **cols, column_info *keys);
 
-static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r );
-static struct expr * EXPR_column( LPWSTR );
-static struct expr * EXPR_ival( struct sql_str *, int sign);
-static struct expr * EXPR_sval( struct sql_str *);
-static struct expr * EXPR_wildcard();
+static struct expr * EXPR_complex( void *info, struct expr *l, UINT op, struct expr *r );
+static struct expr * EXPR_unary( void *info, struct expr *l, UINT op );
+static struct expr * EXPR_column( void *info, const column_info *column );
+static struct expr * EXPR_ival( void *info, int val );
+static struct expr * EXPR_sval( void *info, const struct sql_str *str );
+static struct expr * EXPR_wildcard( void *info );
 
 %}
 
@@ -72,49 +76,24 @@ static struct expr * EXPR_wildcard();
 {
     struct sql_str str;
     LPWSTR string;
-    string_list *column_list;
-    value_list *val_list;
+    column_info *column_list;
     MSIVIEW *query;
     struct expr *expr;
     USHORT column_type;
-    create_col_info *column_info;
-    column_assignment update_col_info;
+    int integer;
 }
 
-%token TK_ABORT TK_AFTER TK_AGG_FUNCTION TK_ALL TK_AND TK_AS TK_ASC
-%token TK_BEFORE TK_BEGIN TK_BETWEEN TK_BITAND TK_BITNOT TK_BITOR TK_BY
-%token TK_CASCADE TK_CASE TK_CHAR TK_CHECK TK_CLUSTER TK_COLLATE TK_COLUMN
-%token TK_COMMA TK_COMMENT TK_COMMIT TK_CONCAT TK_CONFLICT 
-%token TK_CONSTRAINT TK_COPY TK_CREATE
-%token TK_DEFAULT TK_DEFERRABLE TK_DEFERRED TK_DELETE TK_DELIMITERS TK_DESC
-%token TK_DISTINCT TK_DOT TK_DROP TK_EACH
-%token TK_ELSE TK_END TK_END_OF_FILE TK_EQ TK_EXCEPT TK_EXPLAIN
-%token TK_FAIL TK_FLOAT TK_FOR TK_FOREIGN TK_FROM TK_FUNCTION
-%token TK_GE TK_GLOB TK_GROUP TK_GT
-%token TK_HAVING TK_HOLD
-%token TK_IGNORE TK_ILLEGAL TK_IMMEDIATE TK_IN TK_INDEX TK_INITIALLY
-%token <str> TK_ID 
-%token TK_INSERT TK_INSTEAD TK_INT 
+%token TK_ALTER TK_AND TK_BY TK_CHAR TK_COMMA TK_CREATE TK_DELETE TK_DROP
+%token TK_DISTINCT TK_DOT TK_EQ TK_FREE TK_FROM TK_GE TK_GT TK_HOLD TK_ADD
+%token <str> TK_ID
+%token TK_ILLEGAL TK_INSERT TK_INT
 %token <str> TK_INTEGER
-%token TK_INTERSECT TK_INTO TK_IS
-%token TK_ISNULL
-%token TK_JOIN TK_JOIN_KW
-%token TK_KEY
-%token TK_LE TK_LIKE TK_LIMIT TK_LONG TK_LONGCHAR TK_LP TK_LSHIFT TK_LT
-%token TK_LOCALIZABLE
-%token TK_MATCH TK_MINUS
-%token TK_NE TK_NOT TK_NOTNULL TK_NULL
-%token TK_OBJECT TK_OF TK_OFFSET TK_ON TK_OR TK_ORACLE_OUTER_JOIN TK_ORDER
-%token TK_PLUS TK_PRAGMA TK_PRIMARY
-%token TK_RAISE TK_REFERENCES TK_REM TK_REPLACE TK_RESTRICT TK_ROLLBACK
-%token TK_ROW TK_RP TK_RSHIFT
-%token TK_SELECT TK_SEMI TK_SET TK_SHORT TK_SLASH TK_SPACE TK_STAR TK_STATEMENT 
+%token TK_INTO TK_IS TK_KEY TK_LE TK_LONG TK_LONGCHAR TK_LP TK_LT
+%token TK_LOCALIZABLE TK_MINUS TK_NE TK_NOT TK_NULL
+%token TK_OBJECT TK_OR TK_ORDER TK_PRIMARY TK_RP
+%token TK_SELECT TK_SET TK_SHORT TK_SPACE TK_STAR
 %token <str> TK_STRING
-%token TK_TABLE TK_TEMP TK_THEN TK_TRANSACTION TK_TRIGGER
-%token TK_UMINUS TK_UNCLOSED_STRING TK_UNION TK_UNIQUE
-%token TK_UPDATE TK_UPLUS TK_USING
-%token TK_VACUUM TK_VALUES TK_VIEW
-%token TK_WHEN TK_WHERE TK_WILDCARD
+%token TK_TABLE TK_TEMPORARY TK_UPDATE TK_VALUES TK_WHERE TK_WILDCARD
 
 /*
  * These are extra tokens used by the lexer but never seen by the
@@ -125,15 +104,21 @@ static struct expr * EXPR_wildcard();
 %nonassoc END_OF_FILE ILLEGAL SPACE UNCLOSED_STRING COMMENT FUNCTION
           COLUMN AGG_FUNCTION.
 
-%type <string> column table id
-%type <column_list> selcollist
-%type <query> query from unorderedsel
-%type <query> oneupdate onedelete oneselect onequery onecreate oneinsert
+%type <string> table tablelist id
+%type <column_list> selcollist column column_and_type column_def table_def
+%type <column_list> column_assignment update_assign_list constlist
+%type <query> query from fromtable selectfrom unorderedsel
+%type <query> oneupdate onedelete oneselect onequery onecreate oneinsert onealter onedrop
 %type <expr> expr val column_val const_val
 %type <column_type> column_type data_type data_type_l data_count
-%type <column_info> column_def table_def
-%type <val_list> constlist
-%type <update_col_info> column_assignment update_assign_list
+%type <integer> number alterop
+
+/* Reference: http://mates.ms.mff.cuni.cz/oracle/doc/ora815nt/server.815/a67779/operator.htm */
+%left TK_OR
+%left TK_AND
+%left TK_NOT
+%left TK_EQ TK_NE TK_LT TK_GT TK_LE TK_GE TK_LIKE
+%right TK_NEGATION
 
 %%
 
@@ -151,46 +136,60 @@ onequery:
   | oneinsert
   | oneupdate
   | onedelete
+  | onealter
+  | onedrop
     ;
 
 oneinsert:
     TK_INSERT TK_INTO table TK_LP selcollist TK_RP TK_VALUES TK_LP constlist TK_RP
-    {
-        SQL_input *sql = (SQL_input*) info;
-        MSIVIEW *insert = NULL; 
+        {
+            SQL_input *sql = (SQL_input*) info;
+            MSIVIEW *insert = NULL;
 
-        INSERT_CreateView( sql->db, &insert, $3, $5, $9, FALSE ); 
-        $$ = insert;
-    }
-  | TK_INSERT TK_INTO table TK_LP selcollist TK_RP TK_VALUES TK_LP constlist TK_RP TK_TEMP
-    {
-        SQL_input *sql = (SQL_input*) info;
-        MSIVIEW *insert = NULL; 
+            INSERT_CreateView( sql->db, &insert, $3, $5, $9, FALSE );
+            if( !insert )
+                YYABORT;
+            $$ = insert;
+        }
+  | TK_INSERT TK_INTO table TK_LP selcollist TK_RP TK_VALUES TK_LP constlist TK_RP TK_TEMPORARY
+        {
+            SQL_input *sql = (SQL_input*) info;
+            MSIVIEW *insert = NULL;
 
-        INSERT_CreateView( sql->db, &insert, $3, $5, $9, TRUE ); 
-        $$ = insert;
-    }
+            INSERT_CreateView( sql->db, &insert, $3, $5, $9, TRUE );
+            if( !insert )
+                YYABORT;
+            $$ = insert;
+        }
     ;
 
 onecreate:
     TK_CREATE TK_TABLE table TK_LP table_def TK_RP
         {
             SQL_input* sql = (SQL_input*) info;
-            MSIVIEW *create = NULL; 
+            MSIVIEW *create = NULL;
+            UINT r;
 
             if( !$5 )
                 YYABORT;
-            CREATE_CreateView( sql->db, &create, $3, $5, FALSE );
+            r = CREATE_CreateView( sql->db, &create, $3, $5, FALSE );
+            if( !create )
+            {
+                sql->r = r;
+                YYABORT;
+            }
             $$ = create;
         }
   | TK_CREATE TK_TABLE table TK_LP table_def TK_RP TK_HOLD
         {
             SQL_input* sql = (SQL_input*) info;
-            MSIVIEW *create = NULL; 
+            MSIVIEW *create = NULL;
 
             if( !$5 )
                 YYABORT;
             CREATE_CreateView( sql->db, &create, $3, $5, TRUE );
+            if( !create )
+                YYABORT;
             $$ = create;
         }
     ;
@@ -199,9 +198,21 @@ oneupdate:
     TK_UPDATE table TK_SET update_assign_list TK_WHERE expr
         {
             SQL_input* sql = (SQL_input*) info;
-            MSIVIEW *update = NULL; 
+            MSIVIEW *update = NULL;
 
-            UPDATE_CreateView( sql->db, &update, $2, &$4, $6 );
+            UPDATE_CreateView( sql->db, &update, $2, $4, $6 );
+            if( !update )
+                YYABORT;
+            $$ = update;
+        }
+  | TK_UPDATE table TK_SET update_assign_list
+        {
+            SQL_input* sql = (SQL_input*) info;
+            MSIVIEW *update = NULL;
+
+            UPDATE_CreateView( sql->db, &update, $2, $4, NULL );
+            if( !update )
+                YYABORT;
             $$ = update;
         }
     ;
@@ -210,17 +221,76 @@ onedelete:
     TK_DELETE from
         {
             SQL_input* sql = (SQL_input*) info;
-            MSIVIEW *delete = NULL; 
+            MSIVIEW *delete = NULL;
 
             DELETE_CreateView( sql->db, &delete, $2 );
+            if( !delete )
+                YYABORT;
             $$ = delete;
         }
     ;
 
+onealter:
+    TK_ALTER TK_TABLE table alterop
+        {
+            SQL_input* sql = (SQL_input*) info;
+            MSIVIEW *alter = NULL;
+
+            ALTER_CreateView( sql->db, &alter, $3, NULL, $4 );
+            if( !alter )
+                YYABORT;
+            $$ = alter;
+        }
+  | TK_ALTER TK_TABLE table TK_ADD column_and_type
+        {
+            SQL_input *sql = (SQL_input *)info;
+            MSIVIEW *alter = NULL;
+
+            ALTER_CreateView( sql->db, &alter, $3, $5, 0 );
+            if (!alter)
+                YYABORT;
+            $$ = alter;
+        }
+  | TK_ALTER TK_TABLE table TK_ADD column_and_type TK_HOLD
+        {
+            SQL_input *sql = (SQL_input *)info;
+            MSIVIEW *alter = NULL;
+
+            ALTER_CreateView( sql->db, &alter, $3, $5, 1 );
+            if (!alter)
+                YYABORT;
+            $$ = alter;
+        }
+    ;
+
+alterop:
+    TK_HOLD
+        {
+            $$ = 1;
+        }
+  | TK_FREE
+        {
+            $$ = -1;
+        }
+  ;
+
+onedrop:
+    TK_DROP TK_TABLE table
+        {
+            SQL_input* sql = (SQL_input*) info;
+            UINT r;
+
+            $$ = NULL;
+            r = DROP_CreateView( sql->db, &$$, $3 );
+            if( r != ERROR_SUCCESS || !$$ )
+                YYABORT;
+        }
+  ;
+
 table_def:
     column_def TK_PRIMARY TK_KEY selcollist
         {
-            if( SQL_MarkPrimaryKeys( $1, $4 ) )
+            if( SQL_MarkPrimaryKeys( &$1, $4 ) )
                 $$ = $1;
             else
                 $$ = NULL;
@@ -228,45 +298,43 @@ table_def:
     ;
 
 column_def:
-    column_def TK_COMMA column column_type
+    column_def TK_COMMA column_and_type
         {
-            create_col_info *ci;
+            column_info *ci;
 
             for( ci = $1; ci->next; ci = ci->next )
                 ;
 
-            ci->next = HeapAlloc( GetProcessHeap(), 0, sizeof *$$ );
-            if( !ci->next )
-            {
-                /* FIXME: free $1 */
-                YYABORT;
-            }
-            ci->next->colname = $3;
-            ci->next->type = $4;
-            ci->next->next = NULL;
-
+            ci->next = $3;
             $$ = $1;
         }
-  | column column_type
+  | column_and_type
         {
-            $$ = HeapAlloc( GetProcessHeap(), 0, sizeof *$$ );
-            if( ! $$ )
-                YYABORT;
-            $$->colname = $1;
-            $$->type = $2;
-            $$->next = NULL;
+            $$ = $1;
+        }
+    ;
+
+column_and_type:
+    column column_type
+        {
+            $$ = $1;
+            $$->type = ($2 | MSITYPE_VALID);
+            $$->temporary = $2 & MSITYPE_TEMPORARY ? TRUE : FALSE;
         }
     ;
 
 column_type:
     data_type_l
         {
-            $$ = $1 | MSITYPE_VALID;
+            $$ = $1;
         }
   | data_type_l TK_LOCALIZABLE
         {
-            FIXME("LOCALIZABLE ignored\n");
-            $$ = $1 | MSITYPE_VALID;
+            $$ = $1 | MSITYPE_LOCALIZABLE;
+        }
+  | data_type_l TK_TEMPORARY
+        {
+            $$ = $1 | MSITYPE_TEMPORARY;
         }
     ;
 
@@ -292,15 +360,15 @@ data_type:
         }
   | TK_LONGCHAR
         {
-            $$ = 2;
+            $$ = MSITYPE_STRING | 0x400;
         }
   | TK_SHORT
         {
-            $$ = 2;
+            $$ = 2 | 0x400;
         }
   | TK_INT
         {
-            $$ = 2;
+            $$ = 2 | 0x400;
         }
   | TK_LONG
         {
@@ -308,95 +376,82 @@ data_type:
         }
   | TK_OBJECT
         {
-            $$ = 0;
+            $$ = MSITYPE_STRING | MSITYPE_VALID;
         }
     ;
 
 data_count:
-    TK_INTEGER
+    number
         {
-            SQL_input* sql = (SQL_input*) info;
-            int val = SQL_getint(sql);
-            if( ( val > 255 ) || ( val < 0 ) )
+            if( ( $1 > 255 ) || ( $1 < 0 ) )
                 YYABORT;
-            $$ = val;
+            $$ = $1;
         }
     ;
 
 oneselect:
     unorderedsel TK_ORDER TK_BY selcollist
         {
-            SQL_input* sql = (SQL_input*) info;
+            UINT r;
 
-            $$ = NULL;
             if( $4 )
-                ORDER_CreateView( sql->db, &$$, $1, $4 );
-            else
-                $$ = $1;
-            if( !$$ )
-                YYABORT;
+            {
+                r = $1->ops->sort( $1, $4 );
+                if ( r != ERROR_SUCCESS)
+                    YYABORT;
+            }
+
+            $$ = $1;
         }
   | unorderedsel
     ;
 
 unorderedsel:
-    TK_SELECT selcollist from 
+    TK_SELECT selectfrom
+        {
+            $$ = $2;
+        }
+  | TK_SELECT TK_DISTINCT selectfrom
         {
             SQL_input* sql = (SQL_input*) info;
-            if( !$3 )
-                YYABORT;
-            if( $2 )
+            UINT r;
+
+            $$ = NULL;
+            r = DISTINCT_CreateView( sql->db, &$$, $3 );
+            if (r != ERROR_SUCCESS)
             {
-                $$ = do_one_select( sql->db, $3, $2 );
-                if( !$$ )
-                    YYABORT;
+                $3->ops->delete($3);
+                YYABORT;
             }
-            else
-                $$ = $3;
         }
-  | TK_SELECT TK_DISTINCT selcollist from 
+    ;
+
+selectfrom:
+    selcollist from
         {
             SQL_input* sql = (SQL_input*) info;
-            MSIVIEW *view = $4;
+            UINT r;
 
-            if( !view )
-                YYABORT;
-            if( $3 )
+            $$ = NULL;
+            if( $1 )
             {
-                view = do_one_select( sql->db, view, $3 );
-                if( !view )
+                r = SELECT_CreateView( sql->db, &$$, $2, $1 );
+                if (r != ERROR_SUCCESS)
+                {
+                    $2->ops->delete($2);
                     YYABORT;
+                }
             }
-            DISTINCT_CreateView( sql->db, & $$, view );
+            else
+                $$ = $2;
         }
     ;
 
 selcollist:
-    column 
-        { 
-            string_list *list;
-
-            list = HeapAlloc( GetProcessHeap(), 0, sizeof *list );
-            if( !list )
-                YYABORT;
-            list->string = $1;
-            list->next = NULL;
-
-            $$ = list;
-            TRACE("Collist %s\n",debugstr_w($$->string));
-        }
+    column
   | column TK_COMMA selcollist
-        { 
-            string_list *list;
-
-            list = HeapAlloc( GetProcessHeap(), 0, sizeof *list );
-            if( !list )
-                YYABORT;
-            list->string = $1;
-            list->next = $3;
-
-            $$ = list;
-            TRACE("From table: %s\n",debugstr_w($$->string));
+        {
+            $1->next = $3;
         }
   | TK_STAR
         {
@@ -405,32 +460,55 @@ selcollist:
     ;
 
 from:
-    TK_FROM table
-        { 
+    fromtable
+  | fromtable TK_WHERE expr
+        {
             SQL_input* sql = (SQL_input*) info;
             UINT r;
 
             $$ = NULL;
-            TRACE("From table: %s\n",debugstr_w($2));
-            r = TABLE_CreateView( sql->db, $2, & $$ );
+            r = WHERE_CreateView( sql->db, &$$, $1, $3 );
             if( r != ERROR_SUCCESS )
+            {
+                $1->ops->delete( $1 );
                 YYABORT;
+            }
         }
-  | TK_FROM table TK_WHERE expr
-        { 
+    ;
+
+fromtable:
+    TK_FROM table
+        {
             SQL_input* sql = (SQL_input*) info;
-            MSIVIEW *view = NULL;
             UINT r;
 
             $$ = NULL;
-            TRACE("From table: %s\n",debugstr_w($2));
-            r = TABLE_CreateView( sql->db, $2, &view );
-            if( r != ERROR_SUCCESS )
+            r = TABLE_CreateView( sql->db, $2, &$$ );
+            if( r != ERROR_SUCCESS || !$$ )
                 YYABORT;
-            r = WHERE_CreateView( sql->db, &view, view, $4 );
+        }
+  | TK_FROM tablelist
+        {
+            SQL_input* sql = (SQL_input*) info;
+            UINT r;
+
+            r = JOIN_CreateView( sql->db, &$$, $2 );
             if( r != ERROR_SUCCESS )
                 YYABORT;
-            $$ = view;
+        }
+    ;
+
+tablelist:
+    table
+        {
+            $$ = $1;
+        }
+  |
+    table TK_COMMA tablelist
+        {
+            $$ = parser_add_table( info, $3, $1 );
+            if (!$$)
+                YYABORT;
         }
     ;
 
@@ -438,70 +516,66 @@ expr:
     TK_LP expr TK_RP
         {
             $$ = $2;
-        }
-  | column_val TK_EQ column_val
-        {
-            $$ = EXPR_complex( $1, OP_EQ, $3 );
             if( !$$ )
                 YYABORT;
         }
   | expr TK_AND expr
         {
-            $$ = EXPR_complex( $1, OP_AND, $3 );
+            $$ = EXPR_complex( info, $1, OP_AND, $3 );
             if( !$$ )
                 YYABORT;
         }
   | expr TK_OR expr
         {
-            $$ = EXPR_complex( $1, OP_OR, $3 );
+            $$ = EXPR_complex( info, $1, OP_OR, $3 );
             if( !$$ )
                 YYABORT;
         }
   | column_val TK_EQ val
         {
-            $$ = EXPR_complex( $1, OP_EQ, $3 );
+            $$ = EXPR_complex( info, $1, OP_EQ, $3 );
             if( !$$ )
                 YYABORT;
         }
   | column_val TK_GT val
         {
-            $$ = EXPR_complex( $1, OP_GT, $3 );
+            $$ = EXPR_complex( info, $1, OP_GT, $3 );
             if( !$$ )
                 YYABORT;
         }
   | column_val TK_LT val
         {
-            $$ = EXPR_complex( $1, OP_LT, $3 );
+            $$ = EXPR_complex( info, $1, OP_LT, $3 );
             if( !$$ )
                 YYABORT;
         }
   | column_val TK_LE val
         {
-            $$ = EXPR_complex( $1, OP_LE, $3 );
+            $$ = EXPR_complex( info, $1, OP_LE, $3 );
             if( !$$ )
                 YYABORT;
         }
   | column_val TK_GE val
         {
-            $$ = EXPR_complex( $1, OP_GE, $3 );
+            $$ = EXPR_complex( info, $1, OP_GE, $3 );
             if( !$$ )
                 YYABORT;
         }
   | column_val TK_NE val
         {
-            $$ = EXPR_complex( $1, OP_NE, $3 );
+            $$ = EXPR_complex( info, $1, OP_NE, $3 );
             if( !$$ )
                 YYABORT;
         }
   | column_val TK_IS TK_NULL
         {
-            $$ = EXPR_complex( $1, OP_ISNULL, NULL );
+            $$ = EXPR_unary( info, $1, OP_ISNULL );
             if( !$$ )
                 YYABORT;
         }
   | column_val TK_IS TK_NOT TK_NULL
         {
-            $$ = EXPR_complex( $1, OP_NOTNULL, NULL );
+            $$ = EXPR_unary( info, $1, OP_NOTNULL );
             if( !$$ )
                 YYABORT;
         }
@@ -515,27 +589,18 @@ val:
 constlist:
     const_val
         {
-            value_list *vals;
-
-            vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals );
-            if( vals )
-            {
-                vals->val = $1;
-                vals->next = NULL;
-            }
-            $$ = vals;
+            $$ = parser_alloc_column( info, NULL, NULL );
+            if( !$$ )
+                YYABORT;
+            $$->val = $1;
         }
   | const_val TK_COMMA constlist
         {
-            value_list *vals;
-
-            vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals );
-            if( vals )
-            {
-                vals->val = $1;
-                vals->next = $3;
-            }
-            $$ = vals;
+            $$ = parser_alloc_column( info, NULL, NULL );
+            if( !$$ )
+                YYABORT;
+            $$->val = $1;
+            $$->next = $3;
         }
     ;
 
@@ -543,62 +608,67 @@ update_assign_list:
     column_assignment
   | column_assignment TK_COMMA update_assign_list
         {
-            $1.col_list->next = $3.col_list;
-            $1.val_list->next = $3.val_list;
             $$ = $1;
+            $$->next = $3;
         }
     ;
 
 column_assignment:
     column TK_EQ const_val
         {
-            $$.col_list = HeapAlloc( GetProcessHeap(), 0, sizeof *$$.col_list );
-            if( !$$.col_list )
-                YYABORT;
-            $$.col_list->string = $1;
-            $$.col_list->next = NULL;
-            $$.val_list = HeapAlloc( GetProcessHeap(), 0, sizeof *$$.val_list );
-            if( !$$.val_list )
-                YYABORT;
-            $$.val_list->val = $3;
-            $$.val_list->next = 0;
+            $$ = $1;
+            $$->val = $3;
         }
     ;
 
 const_val:
-    TK_INTEGER
+    number
         {
-            $$ = EXPR_ival( &$1, 1 );
+            $$ = EXPR_ival( info, $1 );
+            if( !$$ )
+                YYABORT;
         }
-  | TK_MINUS  TK_INTEGER
+  | TK_MINUS number %prec TK_NEGATION
         {
-            $$ = EXPR_ival( &$2, -1 );
+            $$ = EXPR_ival( info, -$2 );
+            if( !$$ )
+                YYABORT;
         }
   | TK_STRING
         {
-            $$ = EXPR_sval( &$1 );
+            $$ = EXPR_sval( info, &$1 );
+            if( !$$ )
+                YYABORT;
         }
   | TK_WILDCARD
         {
-            $$ = EXPR_wildcard();
+            $$ = EXPR_wildcard( info );
+            if( !$$ )
+                YYABORT;
         }
     ;
 
 column_val:
-    column 
+    column
         {
-            $$ = EXPR_column( $1 );
+            $$ = EXPR_column( info, $1 );
+            if( !$$ )
+                YYABORT;
         }
     ;
 
 column:
     table TK_DOT id
         {
-            $$ = $3;  /* FIXME */
+            $$ = parser_alloc_column( info, $1, $3 );
+            if( !$$ )
+                YYABORT;
         }
   | id
         {
-            $$ = $1;
+            $$ = parser_alloc_column( info, NULL, $1 );
+            if( !$$ )
+                YYABORT;
         }
     ;
 
@@ -612,13 +682,64 @@ table:
 id:
     TK_ID
         {
-            $$ = SQL_getstring( &$1 );
+            if ( SQL_getstring( info, &$1, &$$ ) != ERROR_SUCCESS || !$$ )
+                YYABORT;
+        }
+    ;
+
+number:
+    TK_INTEGER
+        {
+            $$ = SQL_getint( info );
         }
     ;
 
 %%
 
-int SQL_lex( void *SQL_lval, SQL_input *sql)
+static LPWSTR parser_add_table( void *info, LPCWSTR list, LPCWSTR table )
+{
+    static const WCHAR space[] = {' ',0};
+    DWORD len = strlenW( list ) + strlenW( table ) + 2;
+    LPWSTR ret;
+
+    ret = parser_alloc( info, len * sizeof(WCHAR) );
+    if( ret )
+    {
+        strcpyW( ret, list );
+        strcatW( ret, space );
+        strcatW( ret, table );
+    }
+    return ret;
+}
+
+static void *parser_alloc( void *info, unsigned int sz )
+{
+    SQL_input* sql = (SQL_input*) info;
+    struct list *mem;
+
+    mem = msi_alloc( sizeof (struct list) + sz );
+    list_add_tail( sql->mem, mem );
+    return &mem[1];
+}
+
+static column_info *parser_alloc_column( void *info, LPCWSTR table, LPCWSTR column )
+{
+    column_info *col;
+
+    col = parser_alloc( info, sizeof (*col) );
+    if( col )
+    {
+        col->table = table;
+        col->column = column;
+        col->val = NULL;
+        col->type = 0;
+        col->next = NULL;
+    }
+
+    return col;
+}
+
+static int sql_lex( void *SQL_lval, SQL_input *sql )
 {
     int token;
     struct sql_str * str = SQL_lval;
@@ -629,7 +750,7 @@ int SQL_lex( void *SQL_lval, SQL_input *sql)
         if( ! sql->command[sql->n] )
             return 0;  /* end of input */
 
-        TRACE("string : %s\n", debugstr_w(&sql->command[sql->n]));
+        /* TRACE("string : %s\n", debugstr_w(&sql->command[sql->n])); */
         sql->len = sqliteGetToken( &sql->command[sql->n], &token );
         if( sql->len==0 )
             break;
@@ -638,60 +759,64 @@ int SQL_lex( void *SQL_lval, SQL_input *sql)
     }
     while( token == TK_SPACE );
 
-    TRACE("token : %d (%s)\n", token, debugstr_wn(&sql->command[sql->n], sql->len));
-    
+    /* TRACE("token : %d (%s)\n", token, debugstr_wn(&sql->command[sql->n], sql->len)); */
+
     return token;
 }
 
-LPWSTR SQL_getstring( struct sql_str *strdata)
+UINT SQL_getstring( void *info, const struct sql_str *strdata, LPWSTR *str )
 {
     LPCWSTR p = strdata->data;
     UINT len = strdata->len;
-    LPWSTR str;
+
+    /* match quotes */
+    if( ( (p[0]=='`') && (p[len-1]!='`') ) ||
+        ( (p[0]=='\'') && (p[len-1]!='\'') ) )
+        return ERROR_FUNCTION_FAILED;
 
     /* if there's quotes, remove them */
-    if( ( (p[0]=='`') && (p[len-1]=='`') ) || 
+    if( ( (p[0]=='`') && (p[len-1]=='`') ) ||
         ( (p[0]=='\'') && (p[len-1]=='\'') ) )
     {
         p++;
         len -= 2;
     }
-    str = HeapAlloc( GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
-    if(!str )
-        return str;
-    memcpy(str, p, len*sizeof(WCHAR) );
-    str[len]=0;
+    *str = parser_alloc( info, (len + 1)*sizeof(WCHAR) );
+    if( !*str )
+        return ERROR_OUTOFMEMORY;
+    memcpy( *str, p, len*sizeof(WCHAR) );
+    (*str)[len]=0;
 
-    return str;
+    return ERROR_SUCCESS;
 }
 
-INT SQL_getint( SQL_input *sql )
+INT SQL_getint( void *info )
 {
+    SQL_input* sql = (SQL_input*) info;
     LPCWSTR p = &sql->command[sql->n];
+    INT i, r = 0;
 
-    return atoiW( p );
-}
+    for( i=0; i<sql->len; i++ )
+    {
+        if( '0' > p[i] || '9' < p[i] )
+        {
+            ERR("should only be numbers here!\n");
+            break;
+        }
+        r = (p[i]-'0') + r*10;
+    }
 
-int SQL_error(const char *str)
-{
-    return 0;
+    return r;
 }
 
-static MSIVIEW *do_one_select( MSIDATABASE *db, MSIVIEW *in, 
-                               string_list *columns )
+static int sql_error( const char *str )
 {
-    MSIVIEW *view = NULL;
-
-    SELECT_CreateView( db, &view, in, columns );
-    delete_string_list( columns );
-    if( !view )
-        ERR("Error creating select query\n");
-    return view;
+    return 0;
 }
 
-static struct expr * EXPR_wildcard()
+static struct expr * EXPR_wildcard( void *info )
 {
-    struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
+    struct expr *e = parser_alloc( info, sizeof *e );
     if( e )
     {
         e->type = EXPR_WILDCARD;
@@ -699,9 +824,9 @@ static struct expr * EXPR_wildcard()
     return e;
 }
 
-static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r )
+static struct expr * EXPR_complex( void *info, struct expr *l, UINT op, struct expr *r )
 {
-    struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
+    struct expr *e = parser_alloc( info, sizeof *e );
     if( e )
     {
         e->type = EXPR_COMPLEX;
@@ -712,99 +837,111 @@ static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r )
     return e;
 }
 
-static struct expr * EXPR_column( LPWSTR str )
+static struct expr * EXPR_unary( void *info, struct expr *l, UINT op )
 {
-    struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
+    struct expr *e = parser_alloc( info, sizeof *e );
     if( e )
     {
-        e->type = EXPR_COLUMN;
-        e->u.sval = str;
+        e->type = EXPR_UNARY;
+        e->u.expr.left = l;
+        e->u.expr.op = op;
+        e->u.expr.right = NULL;
     }
     return e;
 }
 
-static struct expr * EXPR_ival( struct sql_str *str , int sign)
+static struct expr * EXPR_column( void *info, const column_info *column )
 {
-    struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
+    struct expr *e = parser_alloc( info, sizeof *e );
     if( e )
     {
-        e->type = EXPR_IVAL;
-        e->u.ival = atoiW( str->data ) * sign;
+        e->type = EXPR_COLUMN;
+        e->u.sval = column->column;
     }
     return e;
 }
 
-static struct expr * EXPR_sval( struct sql_str *str )
+static struct expr * EXPR_ival( void *info, int val )
 {
-    struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
+    struct expr *e = parser_alloc( info, sizeof *e );
     if( e )
     {
-        e->type = EXPR_SVAL;
-        e->u.sval = SQL_getstring( str );
+        e->type = EXPR_IVAL;
+        e->u.ival = val;
     }
     return e;
 }
 
-void delete_expr( struct expr *e )
+static struct expr * EXPR_sval( void *info, const struct sql_str *str )
 {
-    if( !e )
-        return;
-    if( e->type == EXPR_COMPLEX )
+    struct expr *e = parser_alloc( info, sizeof *e );
+    if( e )
     {
-        delete_expr( e->u.expr.left );
-        delete_expr( e->u.expr.right );
+        e->type = EXPR_SVAL;
+        if( SQL_getstring( info, str, (LPWSTR *)&e->u.sval ) != ERROR_SUCCESS )
+            return NULL; /* e will be freed by query destructor */
     }
-    else if( e->type == EXPR_SVAL )
-        HeapFree( GetProcessHeap(), 0, e->u.sval );
-    HeapFree( GetProcessHeap(), 0, e );
+    return e;
 }
 
-void delete_string_list( string_list *sl )
+static void swap_columns( column_info **cols, column_info *A, int idx )
 {
-    while( sl )
-    {
-        string_list *t = sl->next;
-        HeapFree( GetProcessHeap(), 0, sl->string );
-        HeapFree( GetProcessHeap(), 0, sl );
-        sl = t;
-    }
-}
+    column_info *preA = NULL, *preB = NULL, *B, *ptr;
+    int i = 0;
 
-void delete_value_list( value_list *vl )
-{
-    while( vl )
+    B = NULL;
+    ptr = *cols;
+    while( ptr )
     {
-        value_list *t = vl->next;
-        delete_expr( vl->val );
-        HeapFree( GetProcessHeap(), 0, vl );
-        vl = t;
+        if( i++ == idx )
+            B = ptr;
+        else if( !B )
+            preB = ptr;
+
+        if( ptr->next == A )
+            preA = ptr;
+
+        ptr = ptr->next;
     }
+
+    if( preB ) preB->next = A;
+    if( preA ) preA->next = B;
+    ptr = A->next;
+    A->next = B->next;
+    B->next = ptr;
+    if( idx == 0 )
+      *cols = A;
 }
 
-static BOOL SQL_MarkPrimaryKeys( create_col_info *cols,
-                                 string_list *keys )
+static BOOL SQL_MarkPrimaryKeys( column_info **cols,
+                                 column_info *keys )
 {
-    string_list *k;
+    column_info *k;
     BOOL found = TRUE;
+    int count;
 
-    for( k = keys; k && found; k = k->next )
+    for( k = keys, count = 0; k && found; k = k->next, count++ )
     {
-        create_col_info *c;
+        column_info *c;
+        int idx;
 
         found = FALSE;
-        for( c = cols; c && !found; c = c->next )
+        for( c = *cols, idx = 0; c && !found; c = c->next, idx++ )
         {
-             if( lstrcmpW( k->string, c->colname ) )
-                 continue;
-             c->type |= MSITYPE_KEY;
-             found = TRUE;
+            if( lstrcmpW( k->column, c->column ) )
+                continue;
+            c->type |= MSITYPE_KEY;
+            found = TRUE;
+            if (idx != count)
+                swap_columns( cols, c, count );
         }
     }
 
     return found;
 }
 
-UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phview )
+UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phview,
+                   struct list *mem )
 {
     SQL_input sql;
     int r;
@@ -815,17 +952,21 @@ UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phview )
     sql.command = command;
     sql.n = 0;
     sql.len = 0;
+    sql.r = ERROR_BAD_QUERY_SYNTAX;
     sql.view = phview;
+    sql.mem = mem;
 
-    r = SQL_parse(&sql);
+    r = sql_parse(&sql);
 
     TRACE("Parse returned %d\n", r);
     if( r )
     {
-        if( *sql.view )
-            (*sql.view)->ops->delete( *sql.view );
-        *sql.view = NULL;
-        return ERROR_BAD_QUERY_SYNTAX;
+        if (*sql.view)
+        {
+            (*sql.view)->ops->delete(*sql.view);
+            *sql.view = NULL;
+        }
+        return sql.r;
     }
 
     return ERROR_SUCCESS;