Something went wrong. Try again.
Reactos
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019%{/* * Implementation of the Microsoft Installer (msi.dll) * * Copyright 2002-2004 Mike McCormack for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */#include <stdarg.h>#include <stdio.h>#include <stdlib.h>#include "windef.h"#include "winbase.h"#include "query.h"#include "wine/list.h"#include "wine/debug.h"WINE_DEFAULT_DEBUG_CHANNEL(msi);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 int sql_error( SQL_input *info, const char *str);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( column_info **cols, column_info *keys);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 );#define PARSER_BUBBLE_UP_VIEW( sql, result, current_view ) \ *sql->view = current_view; \ result = current_view%}%lex-param { SQL_input *info }%parse-param { SQL_input *info }%define api.prefix {sql_}%define api.pure%union{ struct sql_str str; LPWSTR string; column_info *column_list; MSIVIEW *query; struct expr *expr; USHORT column_type; int integer;}%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_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_TEMPORARY TK_UPDATE TK_VALUES TK_WHERE TK_WILDCARD/* * These are extra tokens used by the lexer but never seen by the * parser. We put them in a rule so that the parser generator will * add them to the parse.h output file. * */%nonassoc END_OF_FILE ILLEGAL SPACE UNCLOSED_STRING COMMENT FUNCTION COLUMN AGG_FUNCTION.%type <string> table tablelist id string%type <column_list> selcollist collist selcolumn column column_and_type column_def table_def%type <column_list> column_assignment update_assign_list constlist%type <query> query from selectfrom unorderdfrom%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 <integer> number alterop%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%%query: onequery { SQL_input* sql = (SQL_input*) info; *sql->view = $1; } ;onequery: oneselect | onecreate | oneinsert | oneupdate | onedelete | onealter | onedrop ;oneinsert: TK_INSERT TK_INTO table TK_LP collist TK_RP TK_VALUES TK_LP constlist TK_RP { SQL_input *sql = (SQL_input*) info; MSIVIEW *insert = NULL; INSERT_CreateView( sql->db, &insert, $3, $5, $9, FALSE ); if( !insert ) YYABORT; PARSER_BUBBLE_UP_VIEW( sql, $$, insert ); } | TK_INSERT TK_INTO table TK_LP collist 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 ); if( !insert ) YYABORT; PARSER_BUBBLE_UP_VIEW( sql, $$, insert ); } ;onecreate: TK_CREATE TK_TABLE table TK_LP table_def TK_RP { SQL_input* sql = (SQL_input*) info; MSIVIEW *create = NULL; UINT r; if( !$5 ) YYABORT; r = CREATE_CreateView( sql->db, &create, $3, $5, FALSE ); if( !create ) { sql->r = r; YYABORT; } PARSER_BUBBLE_UP_VIEW( sql, $$, create ); } | TK_CREATE TK_TABLE table TK_LP table_def TK_RP TK_HOLD { SQL_input* sql = (SQL_input*) info; MSIVIEW *create = NULL; if( !$5 ) YYABORT; CREATE_CreateView( sql->db, &create, $3, $5, TRUE ); if( !create ) YYABORT; PARSER_BUBBLE_UP_VIEW( sql, $$, create ); } ;oneupdate: TK_UPDATE table TK_SET update_assign_list TK_WHERE expr { SQL_input* sql = (SQL_input*) info; MSIVIEW *update = NULL; UPDATE_CreateView( sql->db, &update, $2, $4, $6 ); if( !update ) YYABORT; PARSER_BUBBLE_UP_VIEW( sql, $$, 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; PARSER_BUBBLE_UP_VIEW( sql, $$, update ); } ;onedelete: TK_DELETE from { SQL_input* sql = (SQL_input*) info; MSIVIEW *delete = NULL; DELETE_CreateView( sql->db, &delete, $2 ); if( !delete ) YYABORT; PARSER_BUBBLE_UP_VIEW( sql, $$, 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; PARSER_BUBBLE_UP_VIEW( sql, $$, 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; PARSER_BUBBLE_UP_VIEW( sql, $$, 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; PARSER_BUBBLE_UP_VIEW( sql, $$, alter ); } ;alterop: TK_HOLD { $$ = 1; } | TK_FREE { $$ = -1; } ;onedrop: TK_DROP TK_TABLE table { SQL_input* sql = (SQL_input*) info; MSIVIEW* drop = NULL; UINT r; r = DROP_CreateView( sql->db, &drop, $3 ); if( r != ERROR_SUCCESS || !$$ ) YYABORT; PARSER_BUBBLE_UP_VIEW( sql, $$, drop ); } ;table_def: column_def TK_PRIMARY TK_KEY collist { if( SQL_MarkPrimaryKeys( &$1, $4 ) ) $$ = $1; else $$ = NULL; } ;column_def: column_def TK_COMMA column_and_type { column_info *ci; for( ci = $1; ci->next; ci = ci->next ) ; ci->next = $3; $$ = $1; } | column_and_type { $$ = $1; } ;column_and_type: column column_type { $$ = $1; $$->type = ($2 | MSITYPE_VALID); } ;column_type: data_type_l { $$ = $1; } | data_type_l TK_LOCALIZABLE { $$ = $1 | MSITYPE_LOCALIZABLE; } | data_type_l TK_TEMPORARY { $$ = $1 | MSITYPE_TEMPORARY; } ;data_type_l: data_type { $$ |= MSITYPE_NULLABLE; } | data_type TK_NOT TK_NULL { $$ = $1; } ;data_type: TK_CHAR { $$ = MSITYPE_STRING | 0x400; } | TK_CHAR TK_LP data_count TK_RP { $$ = MSITYPE_STRING | 0x400 | $3; } | TK_LONGCHAR { $$ = MSITYPE_STRING | 0x400; } | TK_SHORT { $$ = 2 | 0x400; } | TK_INT { $$ = 2 | 0x400; } | TK_LONG { $$ = 4; } | TK_OBJECT { $$ = MSITYPE_STRING | MSITYPE_VALID; } ;data_count: number { if( ( $1 > 255 ) || ( $1 < 0 ) ) YYABORT; $$ = $1; } ;oneselect: TK_SELECT selectfrom { $$ = $2; } | TK_SELECT TK_DISTINCT selectfrom { SQL_input* sql = (SQL_input*) info; MSIVIEW* distinct = NULL; UINT r; r = DISTINCT_CreateView( sql->db, &distinct, $3 ); if (r != ERROR_SUCCESS) YYABORT; PARSER_BUBBLE_UP_VIEW( sql, $$, distinct ); } ;selectfrom: selcollist from { SQL_input* sql = (SQL_input*) info; MSIVIEW* select = NULL; UINT r; if( $1 ) { r = SELECT_CreateView( sql->db, &select, $2, $1 ); if (r != ERROR_SUCCESS) YYABORT; PARSER_BUBBLE_UP_VIEW( sql, $$, select ); } else $$ = $2; } ;selcollist: selcolumn | selcolumn TK_COMMA selcollist { $1->next = $3; } | TK_STAR { $$ = NULL; } ;collist: column | column TK_COMMA collist { $1->next = $3; } | TK_STAR { $$ = NULL; } ;from: TK_FROM table { SQL_input* sql = (SQL_input*) info; MSIVIEW* table = NULL; UINT r; r = TABLE_CreateView( sql->db, $2, &table ); if( r != ERROR_SUCCESS || !$$ ) YYABORT; PARSER_BUBBLE_UP_VIEW( sql, $$, table ); } | unorderdfrom TK_ORDER TK_BY collist { UINT r; if( $4 ) { r = $1->ops->sort( $1, $4 ); if ( r != ERROR_SUCCESS) YYABORT; } $$ = $1; } | unorderdfrom ;unorderdfrom: TK_FROM tablelist { SQL_input* sql = (SQL_input*) info; MSIVIEW* where = NULL; UINT r; r = WHERE_CreateView( sql->db, &where, $2, NULL ); if( r != ERROR_SUCCESS ) YYABORT; PARSER_BUBBLE_UP_VIEW( sql, $$, where ); } | TK_FROM tablelist TK_WHERE expr { SQL_input* sql = (SQL_input*) info; MSIVIEW* where = NULL; UINT r; r = WHERE_CreateView( sql->db, &where, $2, $4 ); if( r != ERROR_SUCCESS ) YYABORT; PARSER_BUBBLE_UP_VIEW( sql, $$, where ); } ;tablelist: table { $$ = $1; } | table TK_COMMA tablelist { $$ = parser_add_table( info, $3, $1 ); if (!$$) YYABORT; } ;expr: TK_LP expr TK_RP { $$ = $2; if( !$$ ) YYABORT; } | expr TK_AND expr { $$ = EXPR_complex( info, $1, OP_AND, $3 ); if( !$$ ) YYABORT; } | expr TK_OR expr { $$ = EXPR_complex( info, $1, OP_OR, $3 ); if( !$$ ) YYABORT; } | column_val TK_EQ val { $$ = EXPR_complex( info, $1, OP_EQ, $3 ); if( !$$ ) YYABORT; } | column_val TK_GT val { $$ = EXPR_complex( info, $1, OP_GT, $3 ); if( !$$ ) YYABORT; } | column_val TK_LT val { $$ = EXPR_complex( info, $1, OP_LT, $3 ); if( !$$ ) YYABORT; } | column_val TK_LE val { $$ = EXPR_complex( info, $1, OP_LE, $3 ); if( !$$ ) YYABORT; } | column_val TK_GE val { $$ = EXPR_complex( info, $1, OP_GE, $3 ); if( !$$ ) YYABORT; } | column_val TK_NE val { $$ = EXPR_complex( info, $1, OP_NE, $3 ); if( !$$ ) YYABORT; } | column_val TK_IS TK_NULL { $$ = EXPR_unary( info, $1, OP_ISNULL ); if( !$$ ) YYABORT; } | column_val TK_IS TK_NOT TK_NULL { $$ = EXPR_unary( info, $1, OP_NOTNULL ); if( !$$ ) YYABORT; } ;val: column_val | const_val ;constlist: const_val { $$ = parser_alloc_column( info, NULL, NULL ); if( !$$ ) YYABORT; $$->val = $1; } | const_val TK_COMMA constlist { $$ = parser_alloc_column( info, NULL, NULL ); if( !$$ ) YYABORT; $$->val = $1; $$->next = $3; } ;update_assign_list: column_assignment | column_assignment TK_COMMA update_assign_list { $$ = $1; $$->next = $3; } ;column_assignment: column TK_EQ const_val { $$ = $1; $$->val = $3; } ;const_val: number { $$ = EXPR_ival( info, $1 ); if( !$$ ) YYABORT; } | TK_MINUS number %prec TK_NEGATION { $$ = EXPR_ival( info, -$2 ); if( !$$ ) YYABORT; } | TK_STRING { $$ = EXPR_sval( info, &$1 ); if( !$$ ) YYABORT; } | TK_WILDCARD { $$ = EXPR_wildcard( info ); if( !$$ ) YYABORT; } | TK_NULL { $$ = EXPR_sval( info, NULL ); if ( !$$ ) YYABORT; } ;column_val: column { $$ = EXPR_column( info, $1 ); if( !$$ ) YYABORT; } ;column: table TK_DOT id { $$ = parser_alloc_column( info, $1, $3 ); if( !$$ ) YYABORT; } | id { $$ = parser_alloc_column( info, NULL, $1 ); if( !$$ ) YYABORT; } ;selcolumn: table TK_DOT id { $$ = parser_alloc_column( info, $1, $3 ); if( !$$ ) YYABORT; } | id { $$ = parser_alloc_column( info, NULL, $1 ); if( !$$ ) YYABORT; } | string { $$ = parser_alloc_column( info, NULL, $1 ); if( !$$ ) YYABORT; } ;table: id { $$ = $1; } ;id: TK_ID { if ( SQL_getstring( info, &$1, &$$ ) != ERROR_SUCCESS || !$$ ) YYABORT; } ;string: TK_STRING { if ( SQL_getstring( info, &$1, &$$ ) != ERROR_SUCCESS || !$$ ) YYABORT; } ;number: TK_INTEGER { $$ = SQL_getint( info ); } ;%%static LPWSTR parser_add_table( void *info, LPCWSTR list, LPCWSTR table ){ DWORD len = lstrlenW( list ) + lstrlenW( table ) + 2; LPWSTR ret; ret = parser_alloc( info, len * sizeof(WCHAR) ); if( ret ) { lstrcpyW( ret, list ); lstrcatW( ret, L" " ); lstrcatW( ret, table ); } return ret;}static void *parser_alloc( void *info, unsigned int sz ){ SQL_input* sql = (SQL_input*) info; struct list *mem; mem = malloc( 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, skip; struct sql_str * str = SQL_lval; do { sql->n += sql->len; if( ! sql->command[sql->n] ) return 0; /* end of input */ /* TRACE("string : %s\n", debugstr_w(&sql->command[sql->n])); */ sql->len = sqliteGetToken( &sql->command[sql->n], &token, &skip ); if( sql->len==0 ) break; str->data = &sql->command[sql->n]; str->len = sql->len; sql->n += skip; } while( token == TK_SPACE ); /* TRACE("token : %d (%s)\n", token, debugstr_wn(&sql->command[sql->n], sql->len)); */ return token;}UINT SQL_getstring( void *info, const struct sql_str *strdata, LPWSTR *str ){ LPCWSTR p = strdata->data; UINT len = strdata->len; /* match quotes */ if( ( (p[0]=='`') && (p[len-1]!='`') ) || ( (p[0]=='\'') && (p[len-1]!='\'') ) ) return ERROR_FUNCTION_FAILED; /* if there are quotes, remove them */ if( ( (p[0]=='`') && (p[len-1]=='`') ) || ( (p[0]=='\'') && (p[len-1]=='\'') ) ) { p++; len -= 2; } *str = parser_alloc( info, (len + 1)*sizeof(WCHAR) ); if( !*str ) return ERROR_OUTOFMEMORY; memcpy( *str, p, len*sizeof(WCHAR) ); (*str)[len]=0; return ERROR_SUCCESS;}INT SQL_getint( void *info ){ SQL_input* sql = (SQL_input*) info; LPCWSTR p = &sql->command[sql->n]; INT i, r = 0; 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; } return r;}static int sql_error( SQL_input *info, const char *str ){ return 0;}static struct expr * EXPR_wildcard( void *info ){ struct expr *e = parser_alloc( info, sizeof *e ); if( e ) { e->type = EXPR_WILDCARD; } return e;}static struct expr * EXPR_complex( void *info, struct expr *l, UINT op, struct expr *r ){ struct expr *e = parser_alloc( info, sizeof *e ); if( e ) { e->type = EXPR_COMPLEX; e->u.expr.left = l; e->u.expr.op = op; e->u.expr.right = r; } return e;}static struct expr * EXPR_unary( void *info, struct expr *l, UINT op ){ struct expr *e = parser_alloc( info, sizeof *e ); if( e ) { 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_column( void *info, const column_info *column ){ struct expr *e = parser_alloc( info, sizeof *e ); if( e ) { e->type = EXPR_COLUMN; e->u.column.unparsed.column = column->column; e->u.column.unparsed.table = column->table; } return e;}static struct expr * EXPR_ival( void *info, int val ){ struct expr *e = parser_alloc( info, sizeof *e ); if( e ) { e->type = EXPR_IVAL; e->u.ival = val; } return e;}static struct expr * EXPR_sval( void *info, const struct sql_str *str ){ struct expr *e = parser_alloc( info, sizeof *e ); if( e ) { e->type = EXPR_SVAL; if( !str) e->u.sval = NULL; else if( SQL_getstring( info, str, (LPWSTR *)&e->u.sval ) != ERROR_SUCCESS ) return NULL; /* e will be freed by query destructor */ } return e;}static void swap_columns( column_info **cols, column_info *A, int idx ){ column_info *preA = NULL, *preB = NULL, *B, *ptr; int i = 0; B = NULL; ptr = *cols; while( ptr ) { 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( column_info **cols, column_info *keys ){ column_info *k; BOOL found = TRUE; int count; for( k = keys, count = 0; k && found; k = k->next, count++ ) { column_info *c; int idx; found = FALSE; for( c = *cols, idx = 0; c && !found; c = c->next, idx++ ) { if( wcscmp( 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, struct list *mem ){ SQL_input sql; int r; *phview = NULL; sql.db = db; 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); TRACE("Parse returned %d\n", r); if( r ) { if (*sql.view) { (*sql.view)->ops->delete(*sql.view); *sql.view = NULL; } return sql.r; } return ERROR_SUCCESS;}