diff --git a/8F51D3FB-A4C0-4236-8598-A084DCDBCF9D.jpeg b/8F51D3FB-A4C0-4236-8598-A084DCDBCF9D.jpeg new file mode 100644 index 0000000..3798aac Binary files /dev/null and b/8F51D3FB-A4C0-4236-8598-A084DCDBCF9D.jpeg differ diff --git a/PostgreSQL/moviedata/MovieLens1M/movies.dat b/PostgreSQL/moviedata/MovieLens1M/movies.dat index cadebf6..a8b0628 100644 --- a/PostgreSQL/moviedata/MovieLens1M/movies.dat +++ b/PostgreSQL/moviedata/MovieLens1M/movies.dat @@ -352,7 +352,7 @@ 355;Flintstones, The (1994);Children's|Comedy 356;Forrest Gump (1994);Comedy|Romance|War 357;Four Weddings and a Funeral (1994);Comedy|Romance -358;Higher Learning (1995);Drama +358;Higher Learning (1995);Drama 359;I Like It Like That (1994);Comedy|Drama|Romance 360;I Love Trouble (1994);Action|Comedy 361;It Could Happen to You (1994);Drama|Romance @@ -1191,7 +1191,7 @@ 1208;Apocalypse Now (1979);Drama|War 1209;Once Upon a Time in the West (1969);Western 1210;Star Wars: Episode VI - Return of the Jedi (1983);Action|Adventure|Romance|Sci-Fi|War -1211;Wings of Desire (Der Himmel über Berlin) (1987);Comedy|Drama|Romance +1211;Wings of Desire (Der Himmel über Berlin) (1987);Comedy|Drama|Romance 1212;Third Man, The (1949);Mystery|Thriller 1213;GoodFellas (1990);Crime|Drama 1214;Alien (1979);Action|Horror|Sci-Fi|Thriller @@ -1298,7 +1298,7 @@ 1317;I'm Not Rappaport (1996);Comedy 1318;Blue Juice (1995);Comedy|Drama 1319;Kids of Survival (1993);Documentary -1320;Alien³ (1992);Action|Horror|Sci-Fi|Thriller +1320;Alien³ (1992);Action|Horror|Sci-Fi|Thriller 1321;American Werewolf in London, An (1981);Horror 1322;Amityville 1992: It's About Time (1992);Horror 1323;Amityville 3-D (1983);Horror @@ -1381,7 +1381,7 @@ 1401;Ghosts of Mississippi (1996);Drama 1404;Night Falls on Manhattan (1997);Crime|Drama 1405;Beavis and Butt-head Do America (1996);Animation|Comedy -1406;Cérémonie, La (1995);Drama +1406;Cérémonie, La (1995);Drama 1407;Scream (1996);Horror|Thriller 1408;Last of the Mohicans, The (1992);Action|Romance|War 1409;Michael (1996);Comedy|Romance @@ -1530,7 +1530,7 @@ 1569;My Best Friend's Wedding (1997);Comedy|Romance 1570;Tetsuo II: Body Hammer (1992);Sci-Fi 1571;When the Cats Away (Chacun cherche son chat) (1996);Comedy|Romance -1572;Contempt (Le Mépris) (1963);Drama +1572;Contempt (Le Mépris) (1963);Drama 1573;Face/Off (1997);Action|Sci-Fi|Thriller 1574;Fall (1997);Romance 1575;Gabbeh (1996);Drama @@ -1616,7 +1616,7 @@ 1661;Switchback (1997);Thriller 1662;Gang Related (1997);Crime 1663;Stripes (1981);Comedy -1664;Nénette et Boni (1996);Drama +1664;Nénette et Boni (1996);Drama 1665;Bean (1997);Comedy 1666;Hugo Pool (1997);Romance 1667;Mad City (1997);Action|Drama @@ -1688,7 +1688,7 @@ 1738;Vermin (1998);Comedy 1739;3 Ninjas: High Noon On Mega Mountain (1998);Action|Children's 1740;Men of Means (1998);Action|Drama -1741;Midaq Alley (Callejón de los milagros, El) (1995);Drama +1741;Midaq Alley (Callejón de los milagros, El) (1995);Drama 1742;Caught Up (1998);Crime 1743;Arguing the World (1996);Documentary 1744;Firestorm (1998);Action|Adventure|Thriller @@ -1733,7 +1733,7 @@ 1792;U.S. Marshalls (1998);Action|Thriller 1793;Welcome to Woop-Woop (1997);Comedy 1794;Love and Death on Long Island (1997);Comedy|Drama -1795;Callejón de los milagros, El (1995);Drama +1795;Callejón de los milagros, El (1995);Drama 1796;In God's Hands (1998);Action|Drama 1797;Everest (1998);Documentary 1798;Hush (1998);Thriller @@ -1802,7 +1802,7 @@ 1870;Dancer, Texas Pop. 81 (1998);Comedy|Drama 1871;Friend of the Deceased, A (1997);Comedy|Drama 1872;Go Now (1995);Drama -1873;Misérables, Les (1998);Drama +1873;Misérables, Les (1998);Drama 1874;Still Breathing (1997);Comedy|Romance 1875;Clockwatchers (1997);Comedy 1876;Deep Impact (1998);Action|Drama|Sci-Fi|Thriller @@ -1862,7 +1862,7 @@ 1930;Cavalcade (1933);Drama 1931;Mutiny on the Bounty (1935);Adventure 1932;Great Ziegfeld, The (1936);Musical -1933;Life of Émile Zola, The (1937);Drama +1933;Life of Émile Zola, The (1937);Drama 1934;You Can't Take It With You (1938);Comedy 1935;How Green Was My Valley (1941);Drama 1936;Mrs. Miniver (1942);Drama|War @@ -1992,7 +1992,7 @@ 2060;BASEketball (1998);Comedy 2061;Full Tilt Boogie (1997);Documentary 2062;Governess, The (1998);Drama|Romance -2063;Seventh Heaven (Le Septième ciel) (1997);Drama|Romance +2063;Seventh Heaven (Le Septième ciel) (1997);Drama|Romance 2064;Roger & Me (1989);Comedy|Documentary 2065;Purple Rose of Cairo, The (1985);Comedy|Drama|Romance 2066;Out of the Past (1947);Film-Noir @@ -2060,7 +2060,7 @@ 2128;Safe Men (1998);Comedy 2129;Saltmen of Tibet, The (1997);Documentary 2130;Atlantic City (1980);Crime|Drama|Romance -2131;Autumn Sonata (Höstsonaten ) (1978);Drama +2131;Autumn Sonata (Höstsonaten ) (1978);Drama 2132;Who's Afraid of Virginia Woolf? (1966);Drama 2133;Adventures in Babysitting (1987);Adventure|Comedy 2134;Weird Science (1985);Comedy @@ -2104,7 +2104,7 @@ 2172;Strike! (a.k.a. All I Wanna Do, The Hairy Bird) (1998);Comedy 2173;Navigator: A Mediaeval Odyssey, The (1988);Adventure|Fantasy|Sci-Fi 2174;Beetlejuice (1988);Comedy|Fantasy -2175;Déjà Vu (1997);Drama|Romance +2175;Déjà Vu (1997);Drama|Romance 2176;Rope (1948);Thriller 2177;Family Plot (1976);Comedy|Thriller 2178;Frenzy (1972);Thriller @@ -2253,7 +2253,7 @@ 2321;Pleasantville (1998);Comedy 2322;Soldier (1998);Action|Adventure|Sci-Fi|Thriller|War 2323;Cruise, The (1998);Documentary -2324;Life Is Beautiful (La Vita è bella) (1997);Comedy|Drama +2324;Life Is Beautiful (La Vita è bella) (1997);Comedy|Drama 2325;Orgazmo (1997);Comedy 2326;Shattered Image (1998);Drama|Thriller 2327;Tales from the Darkside: The Movie (1990);Horror @@ -2409,10 +2409,10 @@ 2477;Firewalker (1986);Adventure 2478;Three Amigos! (1986);Comedy|Western 2479;Gloria (1999);Drama|Thriller -2480;Dry Cleaning (Nettoyage à sec) (1997);Drama +2480;Dry Cleaning (Nettoyage à sec) (1997);Drama 2481;My Name Is Joe (1998);Drama|Romance 2482;Still Crazy (1998);Comedy|Romance -2483;Day of the Beast, The (El Día de la bestia) (1995);Comedy|Horror|Thriller +2483;Day of the Beast, The (El Día de la bestia) (1995);Comedy|Horror|Thriller 2484;Tinseltown (1998);Comedy 2485;She's All That (1999);Comedy|Romance 2486;24-hour Woman (1998);Drama @@ -2424,7 +2424,7 @@ 2492;20 Dates (1998);Comedy 2493;Harmonists, The (1997);Drama 2494;Last Days, The (1998);Documentary -2495;Fantastic Planet, The (La Planète sauvage) (1973);Animation|Sci-Fi +2495;Fantastic Planet, The (La Planète sauvage) (1973);Animation|Sci-Fi 2496;Blast from the Past (1999);Comedy|Romance 2497;Message in a Bottle (1999);Romance 2498;My Favorite Martian (1999);Comedy|Sci-Fi @@ -2473,7 +2473,7 @@ 2541;Cruel Intentions (1999);Drama 2542;Lock, Stock & Two Smoking Barrels (1998);Comedy|Crime|Thriller 2543;Six Ways to Sunday (1997);Comedy -2544;School of Flesh, The (L' École de la chair) (1998);Drama +2544;School of Flesh, The (L' École de la chair) (1998);Drama 2545;Relax... It's Just Sex (1998);Comedy 2546;Deep End of the Ocean, The (1999);Drama 2547;Harvest (1998);Drama @@ -2504,7 +2504,7 @@ 2572;10 Things I Hate About You (1999);Comedy|Romance 2573;Tango (1998);Drama 2574;Out-of-Towners, The (1999);Comedy -2575;Dreamlife of Angels, The (La Vie rêvée des anges) (1998);Drama +2575;Dreamlife of Angels, The (La Vie rêvée des anges) (1998);Drama 2576;Love, etc. (1996);Drama 2577;Metroland (1997);Comedy|Drama 2578;Sticky Fingers of Time, The (1997);Sci-Fi @@ -2514,13 +2514,13 @@ 2582;Twin Dragons (Shuang long hui) (1992);Action|Comedy 2583;Cookie's Fortune (1999);Mystery 2584;Foolish (1999);Comedy -2585;Lovers of the Arctic Circle, The (Los Amantes del Círculo Polar) (1998);Drama|Romance +2585;Lovers of the Arctic Circle, The (Los Amantes del Círculo Polar) (1998);Drama|Romance 2586;Goodbye, Lover (1999);Comedy|Crime|Thriller 2587;Life (1999);Comedy 2588;Clubland (1998);Drama 2589;Friends & Lovers (1999);Comedy|Drama|Romance 2590;Hideous Kinky (1998);Drama -2591;Jeanne and the Perfect Guy (Jeanne et le garçon formidable) (1998);Comedy|Romance +2591;Jeanne and the Perfect Guy (Jeanne et le garçon formidable) (1998);Comedy|Romance 2592;Joyriders, The (1999);Drama 2593;Monster, The (Il Mostro) (1994);Comedy 2594;Open Your Eyes (Abre los ojos) (1997);Drama|Romance|Sci-Fi @@ -2532,7 +2532,7 @@ 2600;eXistenZ (1999);Action|Sci-Fi|Thriller 2601;Little Bit of Soul, A (1998);Comedy 2602;Mighty Peking Man (Hsing hsing wang) (1977);Adventure|Sci-Fi -2603;Nô (1998);Drama +2603;Nô (1998);Drama 2604;Let it Come Down: The Life of Paul Bowles (1998);Documentary 2605;Entrapment (1999);Crime|Thriller 2606;Idle Hands (1999);Comedy|Horror @@ -2625,7 +2625,7 @@ 2693;Trekkies (1997);Documentary 2694;Big Daddy (1999);Comedy 2695;Boys, The (1997);Drama -2696;Dinner Game, The (Le Dîner de cons) (1998);Comedy +2696;Dinner Game, The (Le Dîner de cons) (1998);Comedy 2697;My Son the Fanatic (1998);Comedy|Drama|Romance 2698;Zone 39 (1997);Sci-Fi 2699;Arachnophobia (1990);Action|Comedy|Sci-Fi|Thriller @@ -2634,7 +2634,7 @@ 2702;Summer of Sam (1999);Drama 2703;Broken Vessels (1998);Drama 2704;Lovers on the Bridge, The (Les Amants du Pont-Neuf) (1991);Drama|Romance -2705;Late August, Early September (Fin août, début septembre) (1998);Drama +2705;Late August, Early September (Fin août, début septembre) (1998);Drama 2706;American Pie (1999);Comedy 2707;Arlington Road (1999);Thriller 2708;Autumn Tale, An (Conte d'automne) (1998);Romance @@ -2671,7 +2671,7 @@ 2739;Color Purple, The (1985);Drama 2740;Kindred, The (1986);Horror 2741;No Mercy (1986);Action|Thriller -2742;Ménage (Tenue de soirée) (1986);Comedy|Drama +2742;Ménage (Tenue de soirée) (1986);Comedy|Drama 2743;Native Son (1986);Drama 2744;Otello (1986);Drama 2745;Mission, The (1986);Drama @@ -2689,7 +2689,7 @@ 2757;Frances (1982);Drama 2758;Plenty (1985);Drama 2759;Dick (1999);Comedy -2760;Gambler, The (A Játékos) (1997);Drama +2760;Gambler, The (A Játékos) (1997);Drama 2761;Iron Giant, The (1999);Animation|Children's 2762;Sixth Sense, The (1999);Thriller 2763;Thomas Crown Affair, The (1999);Action|Thriller @@ -2798,7 +2798,7 @@ 2866;Buddy Holly Story, The (1978);Drama 2867;Fright Night (1985);Comedy|Horror 2868;Fright Night Part II (1989);Horror -2869;Separation, The (La Séparation) (1994);Drama +2869;Separation, The (La Séparation) (1994);Drama 2870;Barefoot in the Park (1967);Comedy 2871;Deliverance (1972);Adventure|Thriller 2872;Excalibur (1981);Action|Drama|Fantasy|Romance @@ -2983,7 +2983,7 @@ 3051;Anywhere But Here (1999);Drama 3052;Dogma (1999);Comedy 3053;Messenger: The Story of Joan of Arc, The (1999);Drama|War -3054;Pokémon: The First Movie (1998);Animation|Children's +3054;Pokémon: The First Movie (1998);Animation|Children's 3055;Felicia's Journey (1999);Thriller 3056;Oxygen (1999);Thriller 3057;Where's Marlowe? (1999);Comedy @@ -3156,7 +3156,7 @@ 3224;Woman in the Dunes (Suna no onna) (1964);Drama 3225;Down to You (2000);Comedy|Romance 3226;Hellhounds on My Trail (1999);Documentary -3227;Not Love, Just Frenzy (Más que amor, frenesí) (1996);Comedy|Drama|Thriller +3227;Not Love, Just Frenzy (Más que amor, frenesí) (1996);Comedy|Drama|Thriller 3228;Wirey Spindell (1999);Comedy 3229;Another Man's Poison (1952);Crime|Drama 3230;Odessa File, The (1974);Thriller @@ -3166,11 +3166,11 @@ 3234;Train Ride to Hollywood (1978);Comedy 3235;Where the Buffalo Roam (1980);Comedy 3236;Zachariah (1971);Western -3237;Kestrel's Eye (Falkens öga) (1998);Documentary +3237;Kestrel's Eye (Falkens öga) (1998);Documentary 3238;Eye of the Beholder (1999);Thriller 3239;Isn't She Great? (2000);Comedy 3240;Big Tease, The (1999);Comedy -3241;Cup, The (Phörpa) (1999);Comedy +3241;Cup, The (Phörpa) (1999);Comedy 3242;Santitos (1997);Comedy 3243;Encino Man (1992);Comedy 3244;Goodbye Girl, The (1977);Comedy|Romance @@ -3195,7 +3195,7 @@ 3263;White Men Can't Jump (1992);Comedy 3264;Buffy the Vampire Slayer (1992);Comedy|Horror 3265;Hard-Boiled (Lashou shentan) (1992);Action|Crime -3266;Man Bites Dog (C'est arrivé près de chez vous) (1992);Action|Comedy|Crime|Drama +3266;Man Bites Dog (C'est arrivé près de chez vous) (1992);Action|Comedy|Crime|Drama 3267;Mariachi, El (1992);Action|Thriller 3268;Stop! Or My Mom Will Shoot (1992);Action|Comedy 3269;Forever Young (1992);Adventure|Romance|Sci-Fi @@ -3298,7 +3298,7 @@ 3366;Where Eagles Dare (1969);Action|Adventure|War 3367;Devil's Brigade, The (1968);War 3368;Big Country, The (1958);Romance|Western -3369;Any Number Can Win (Mélodie en sous-sol ) (1963);Crime +3369;Any Number Can Win (Mélodie en sous-sol ) (1963);Crime 3370;Betrayed (1988);Drama|Thriller 3371;Bound for Glory (1976);Drama 3372;Bridge at Remagen, The (1969);Action|War @@ -3345,7 +3345,7 @@ 3413;Impact (1949);Crime|Drama 3414;Love Is a Many-Splendored Thing (1955);Romance 3415;Mirror, The (Zerkalo) (1975);Drama -3416;Trial, The (Le Procès) (1963);Drama +3416;Trial, The (Le Procès) (1963);Drama 3417;Crimson Pirate, The (1952);Adventure|Comedy|Sci-Fi 3418;Thelma & Louise (1991);Action|Drama 3419;Something for Everyone (1970);Comedy|Crime @@ -3461,7 +3461,7 @@ 3529;Postman Always Rings Twice, The (1981);Crime|Thriller 3530;Smoking/No Smoking (1993);Comedy 3531;All the Vermeers in New York (1990);Comedy|Drama|Romance -3532;Freedom for Us (À nous la liberté ) (1931);Comedy +3532;Freedom for Us (À nous la liberté ) (1931);Comedy 3533;Actor's Revenge, An (Yukinojo Henge) (1963);Drama 3534;28 Days (2000);Comedy 3535;American Psycho (2000);Comedy|Horror|Thriller @@ -3521,7 +3521,7 @@ 3589;Kill, Baby... Kill! (Operazione Paura) (1966);Horror 3590;Lords of Flatbush, The (1974);Comedy 3591;Mr. Mom (1983);Comedy|Drama -3592;Time Masters (Les Maîtres du Temps) (1982);Animation|Sci-Fi +3592;Time Masters (Les Maîtres du Temps) (1982);Animation|Sci-Fi 3593;Battlefield Earth (2000);Action|Sci-Fi 3594;Center Stage (2000);Drama 3595;Held Up (2000);Comedy @@ -3574,14 +3574,14 @@ 3642;In Old California (1942);Western 3643;Fighting Seabees, The (1944);Action|Drama|War 3644;Dark Command (1940);Western -3645;Cleo From 5 to 7 (Cléo de 5 à 7) (1962);Drama +3645;Cleo From 5 to 7 (Cléo de 5 à 7) (1962);Drama 3646;Big Momma's House (2000);Comedy 3647;Running Free (2000);Drama 3648;Abominable Snowman, The (1957);Horror|Sci-Fi 3649;American Gigolo (1980);Drama 3650;Anguish (Angustia) (1986);Horror 3651;Blood Spattered Bride, The (La Novia Ensangrentada) (1972);Horror -3652;City of the Living Dead (Paura nella città dei morti viventi) (1980);Horror +3652;City of the Living Dead (Paura nella città dei morti viventi) (1980);Horror 3653;Endless Summer, The (1966);Documentary 3654;Guns of Navarone, The (1961);Action|Drama|War 3655;Blow-Out (La Grande Bouffe) (1973);Drama @@ -3678,7 +3678,7 @@ 3746;Butterfly (La Lengua de las Mariposas) (2000);Drama|War 3747;Jesus' Son (1999);Drama 3748;Match, The (1999);Comedy|Romance -3749;Time Regained (Le Temps Retrouvé) (1999);Drama +3749;Time Regained (Le Temps Retrouvé) (1999);Drama 3750;Boricua's Bond (2000);Drama 3751;Chicken Run (2000);Animation|Children's|Comedy 3752;Me, Myself and Irene (2000);Comedy @@ -3728,7 +3728,7 @@ 3796;Wisdom of Crocodiles, The (a.k.a. Immortality) (2000);Romance|Thriller 3797;In Crowd, The (2000);Thriller 3798;What Lies Beneath (2000);Thriller -3799;Pokémon the Movie 2000 (2000);Animation|Children's +3799;Pokémon the Movie 2000 (2000);Animation|Children's 3800;Criminal Lovers (Les Amants Criminels) (1999);Drama|Romance 3801;Anatomy of a Murder (1959);Drama|Mystery 3802;Freejack (1992);Action|Sci-Fi @@ -3745,7 +3745,7 @@ 3813;Interiors (1978);Drama 3814;Love and Death (1975);Comedy 3816;Official Story, The (La Historia Oficial) (1985);Drama -3817;Other Side of Sunday, The (Søndagsengler) (1996);Comedy|Drama +3817;Other Side of Sunday, The (Søndagsengler) (1996);Comedy|Drama 3818;Pot O' Gold (1941);Comedy|Musical 3819;Tampopo (1986);Comedy 3820;Thomas and the Magic Railroad (2000);Children's @@ -3782,7 +3782,7 @@ 3851;I'm the One That I Want (2000);Comedy 3852;Tao of Steve, The (2000);Comedy 3853;Tic Code, The (1998);Drama -3854;Aimée & Jaguar (1999);Drama|Romance +3854;Aimée & Jaguar (1999);Drama|Romance 3855;Affair of Love, An (Une Liaison Pornographique) (1999);Drama|Romance 3856;Autumn Heart (1999);Drama 3857;Bless the Child (2000);Thriller diff --git a/PostgreSQL/src/backend/nodes/copyfuncs.c b/PostgreSQL/src/backend/nodes/copyfuncs.c index f5b2cd5..06f3cd5 100644 --- a/PostgreSQL/src/backend/nodes/copyfuncs.c +++ b/PostgreSQL/src/backend/nodes/copyfuncs.c @@ -28,6 +28,7 @@ #include "nodes/plannodes.h" #include "nodes/relation.h" #include "utils/datum.h" +#include "../../include/nodes/plannodes.h" /* @@ -402,6 +403,32 @@ _copyIndexOnlyScan(const IndexOnlyScan *from) return newnode; } +/* + * _copyIndexOnlyScan + */ +static RecScan * +_copyRecScan(const RecScan *from) +{ + RecScan *newnode = makeNode(RecScan); + + /* + * copy node superclass fields + */ + + + CopyScanFields((const Scan *) from, (Scan *) newnode); + + /* + * copy remainder of node + */ + + COPY_NODE_FIELD(recommender); + // CopyScanFields((const Scan *) from, (Scan *) newnode); + COPY_NODE_FIELD(subscan); + + return newnode; +} + /* * _copyBitmapIndexScan */ @@ -3829,9 +3856,9 @@ copyObject(const void *from) switch (nodeTag(from)) { - /* - * PLAN NODES - */ + /* + * PLAN NODES + */ case T_PlannedStmt: retval = _copyPlannedStmt(from); break; @@ -3949,6 +3976,9 @@ copyObject(const void *from) case T_PlanInvalItem: retval = _copyPlanInvalItem(from); break; + case T_RecScan: + retval = _copyRecScan(from); + break; /* * PRIMITIVE NODES diff --git a/PostgreSQL/src/backend/optimizer/plan/planner.c b/PostgreSQL/src/backend/optimizer/plan/planner.c index 1c991d3..d9c657f 100644 --- a/PostgreSQL/src/backend/optimizer/plan/planner.c +++ b/PostgreSQL/src/backend/optimizer/plan/planner.c @@ -418,16 +418,25 @@ subquery_planner(PlannerGlobal *glob, Query *parse, /* NEW FOR RECDB */ /* Do expression preprocessing on the user-focused WHERE clause as well. */ - if (parse->recommendStmt) { - RecommendInfo *recInfo; - AttributeInfo *attInfo; + /*In order to Prevent an error from happening while using copy functions + * we do expression preprocessing on range table entries directly*/ - recInfo = (RecommendInfo*) parse->recommendStmt; - attInfo = recInfo->attributes; + foreach(l, parse->rtable) + { + RangeTblEntry *rte = (RangeTblEntry *) lfirst(l); - attInfo->userWhereClause = preprocess_expression(root, - attInfo->userWhereClause, EXPRKIND_QUAL); - } + if (rte->recommender != NULL){ + RecommendInfo *recInfo; + AttributeInfo *attInfo; + + recInfo = (RecommendInfo*) rte->recommender; + attInfo = recInfo->attributes; + + attInfo->userWhereClause = preprocess_expression(root, + attInfo->userWhereClause, EXPRKIND_QUAL); + } + + } foreach(l, parse->windowClause) { diff --git a/PostgreSQL/src/backend/parser/parse_rec.c b/PostgreSQL/src/backend/parser/parse_rec.c index afac2d1..16fdb27 100644 --- a/PostgreSQL/src/backend/parser/parse_rec.c +++ b/PostgreSQL/src/backend/parser/parse_rec.c @@ -30,7 +30,7 @@ static void validateClauses(SelectStmt *stmt); static RecommendInfo* getEventsTable(List *fromClause, Node *recommendClause); static char* getTableRef(ColumnRef *colref, char **colname); static AttributeInfo* getAttributeInfo(char *eventtable, char *userkey, char *itemkey, char *eventval, - RecommendInfo *recInfo); + RecommendInfo *recInfo); static int checkWhereClause(ColumnRef* attribute, RangeVar* recommender, char* userkey, char* eventval); //static void modifyAExpr(Node *currentExpr, char* recname, char* viewname); //static void modifyTargetList(List *target_list, char *recname, char *viewname); @@ -43,6 +43,7 @@ static bool filterfirstrecurse(Node *whereExpr, RecommendInfo *recInfo); static bool tableMatch(RangeVar* table, char* tablename); static Node *makeTrueConst(); static Node *userWhereClause(Node* whereClause, char *userkey); +static RangeVar* getRecommendVar(RangeVar * var); /* * transformRecommendClause - @@ -54,60 +55,60 @@ static Node *userWhereClause(Node* whereClause, char *userkey); */ SelectStmt * transformRecommendClause(ParseState *pstate, List **targetlist, SelectStmt *stmt, - const char *constructName) + const char *constructName) { - RecommendInfo *recInfo; - Node *userWhere; - recInfo = NULL; - - // We need to do some preprocessing and sanity checks. If any of the sanity - // checks fail, we'll throw an error. - validateClauses(stmt); - - // Now that we know the overall query has the right structure, - // it's time to look at the specific information included. - - // Step one: by using the provided information in the RECOMMEND clause, - // we need to determine what the event table is that we intend to use. - // We also need to make sure that all of the RECOMMEND clause columns - // correspond to said events table. - recInfo = getEventsTable(stmt->fromClause, stmt->recommendClause); - - if (!recInfo) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("a valid events table has not been provided"))); - - // Step two: look through the WHERE clause to see if there are any RecScore - // restrictions. If there are, we need to mark this specially. - filterfirst(stmt->whereClause, recInfo); - - // Step three: see if we are joining the user ID or item ID to another table, in - // which case we want to perform a RecJoin. -// applyRecJoin(stmt->whereClause, stmt->fromClause, recInfo); - - // Step four: now that we've verified the correctness of our query, we need to - // see if a recommender already exists for a given table and method. If so, we'll - // reference the created RecModel; if not, we'll build it on the fly from the - // schema of the events table. Either way, we make a note of which of our tables - // will be the basis of our recommender schema. - modifyFrom(stmt, recInfo); - - // Step five: we need to scan the WHERE clause and find which elements pertain - // to the user key; this will save us a lot of unnecessary work later on. We'll - // make a copy of it that we can modify for our purposes. - userWhere = userWhereClause(((Node *) copyObject(stmt->whereClause)), recInfo->attributes->userkey); -// userWhere = userWhereClause(stmt->whereClause, recInfo->attributes->userkey); - recInfo->attributes->userWhereClause = userWhere; - - // There's an additional step, where we add the RECOMMEND clause elements into - // the target list if they aren't there, but we can't perform this step until - // the target list and FROM clauses have been processed, so we'll leave that - // for later. - - // With that done, we put in the changed recInfo and return. - stmt->recommendClause = (Node*) recInfo; - return stmt; + RecommendInfo *recInfo; + Node *userWhere; + recInfo = NULL; + + // We need to do some preprocessing and sanity checks. If any of the sanity + // checks fail, we'll throw an error. + validateClauses(stmt); + + // Now that we know the overall query has the right structure, + // it's time to look at the specific information included. + + // Step one: by using the provided information in the RECOMMEND clause, + // we need to determine what the event table is that we intend to use. + // We also need to make sure that all of the RECOMMEND clause columns + // correspond to said events table. + recInfo = getEventsTable(stmt->fromClause, stmt->recommendClause); + + if (!recInfo) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("a valid events table has not been provided"))); + + // Step two: look through the WHERE clause to see if there are any RecScore + // restrictions. If there are, we need to mark this specially. + filterfirst(stmt->whereClause, recInfo); + + // Step three: see if we are joining the user ID or item ID to another table, in + // which case we want to perform a RecJoin. + // applyRecJoin(stmt->whereClause, stmt->fromClause, recInfo); + + // Step four: now that we've verified the correctness of our query, we need to + // see if a recommender already exists for a given table and method. If so, we'll + // reference the created RecModel; if not, we'll build it on the fly from the + // schema of the events table. Either way, we make a note of which of our tables + // will be the basis of our recommender schema. + modifyFrom(stmt, recInfo); + + // Step five: we need to scan the WHERE clause and find which elements pertain + // to the user key; this will save us a lot of unnecessary work later on. We'll + // make a copy of it that we can modify for our purposes. + userWhere = userWhereClause(((Node *) copyObject(stmt->whereClause)), recInfo->attributes->userkey); + // userWhere = userWhereClause(stmt->whereClause, recInfo->attributes->userkey); + recInfo->attributes->userWhereClause = userWhere; + + // There's an additional step, where we add the RECOMMEND clause elements into + // the target list if they aren't there, but we can't perform this step until + // the target list and FROM clauses have been processed, so we'll leave that + // for later. + + // With that done, we put in the changed recInfo and return. + stmt->recommendClause = (Node*) recInfo; + return stmt; } /* @@ -117,42 +118,63 @@ transformRecommendClause(ParseState *pstate, List **targetlist, SelectStmt *stmt */ static void validateClauses(SelectStmt *stmt) { - // A FROM clause is required. - if (!stmt->fromClause) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("RECOMMEND clause is not allowed without FROM clause"))); - // Numerous other clauses have to not be there. We're very picky. - if (stmt->distinctClause) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("RECOMMEND clause is not allowed with DISTINCT clause"))); - if (stmt->intoClause) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("RECOMMEND clause is not allowed with INTO clause"))); - if (stmt->groupClause) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("RECOMMEND clause is not allowed with GROUP BY clause"))); - if (stmt->havingClause) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("RECOMMEND clause is not allowed with HAVING clause"))); - if (stmt->windowClause) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("RECOMMEND clause is not allowed with WINDOW clause"))); - if (stmt->lockingClause) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("RECOMMEND clause is not allowed with FOR clause"))); - if (stmt->withClause) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("RECOMMEND clause is not allowed with WITH clause"))); + // A FROM clause is required. + if (!stmt->fromClause) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("RECOMMEND clause is not allowed without FROM clause"))); + // Numerous other clauses have to not be there. We're very picky. + if (stmt->distinctClause) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("RECOMMEND clause is not allowed with DISTINCT clause"))); + if (stmt->intoClause) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("RECOMMEND clause is not allowed with INTO clause"))); + if (stmt->groupClause) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("RECOMMEND clause is not allowed with GROUP BY clause"))); + if (stmt->havingClause) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("RECOMMEND clause is not allowed with HAVING clause"))); + if (stmt->windowClause) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("RECOMMEND clause is not allowed with WINDOW clause"))); + if (stmt->lockingClause) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("RECOMMEND clause is not allowed with FOR clause"))); + if (stmt->withClause) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("RECOMMEND clause is not allowed with WITH clause"))); + + return; +} - return; +/* + * getRecommendVar - + * A helper function for getEventsTable, which prevents + * circular linking from happening. + * + * + */ +static RangeVar* getRecommendVar(RangeVar * var){ + RangeVar * newvar = makeNode(RangeVar); + newvar->catalogname = var->catalogname; + newvar->schemaname = var->schemaname; + newvar->relname = var->relname; + newvar->inhOpt = var->inhOpt; + newvar->relpersistence = var->relpersistence; + newvar->alias = var->alias; + newvar->location = var->location; + newvar->recommender = NULL; + + return newvar; } /* @@ -164,112 +186,114 @@ validateClauses(SelectStmt *stmt) { */ static RecommendInfo* getEventsTable(List *fromClause, Node *recommendClause) { - char *usertref, *itemtref, *eventtref; - char *userkey, *itemkey, *eventval; - char *eventtable = NULL; - AttributeInfo *attributes; - bool elem_match = true; - - RecommendInfo *recInfo = (RecommendInfo*) recommendClause; - ColumnRef *usercr = (ColumnRef*) recInfo->userkey; - ColumnRef *itemcr = (ColumnRef*) recInfo->itemkey; - ColumnRef *eventcr = (ColumnRef*) recInfo->eventval; - - // First off, we'll perform sanity checks on the elements - // of the RECOMMEND clause. We need to make sure their - // table references are valid and matching. - userkey = getTableRef(usercr, &usertref); - itemkey = getTableRef(itemcr, &itemtref); - eventval = getTableRef(eventcr, &eventtref); - - // If one element has no table reference, none of them can have - // table references. - if ((usertref && !itemtref) || (!usertref && itemtref)) - elem_match = false; - if ((usertref && !eventtref) || (!usertref && eventtref)) - elem_match = false; - - // If table references exist, they all have to be the same. - if (usertref && elem_match) { - if ((strcmp(usertref,itemtref) != 0) || - (strcmp(usertref,eventtref) != 0)) - elem_match = false; - } - - if (!elem_match) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("elements of RECOMMEND clause must have matching table references"))); - - // Now that we've confirmed the correctness of the RECOMMEND - // clause table references, we will use them to find the event table - // referred to in the FROM clause. If there are table references, that makes - // the task easy; if not, then we can manually check to see if each column - // exists in a specific table. - if (usertref) { - // Let's look for a FROM table element that matches. - ListCell *from_cell; - foreach(from_cell,fromClause) { - Node *from_node = lfirst(from_cell); - if (nodeTag(from_node) == T_RangeVar) { - RangeVar *fromVar; - - fromVar = (RangeVar*) from_node; - if (tableMatch(fromVar,usertref)) { - eventtable = fromVar->relname; - recInfo->recommender = fromVar; - fromVar->recommender = (Node*) recInfo; - break; - } - } - } - } else { - // If we can't easily identify the events table via - // table references, we will do so by cross-referencing the - // column names with the name of each table. - ListCell *from_cell; - foreach(from_cell,fromClause) { - Node *from_node = lfirst(from_cell); - if (nodeTag(from_node) == T_RangeVar) { - RangeVar *fromVar; - - fromVar = (RangeVar*) from_node; - // If all the key columns are in this table... - if (columnExistsInRelation(userkey,fromVar) && - columnExistsInRelation(itemkey,fromVar) && - columnExistsInRelation(eventval,fromVar)) { - // Did we already find a table matching all of - // these columns? If so, that's an error. - if (eventtable) { - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("ambiguous references in RECOMMEND clause"))); - } else { - // Make a note of the name, and also - // do cross-storage of the table. - eventtable = fromVar->relname; - recInfo->recommender = fromVar; - fromVar->recommender = (Node*) recInfo; - } - } - } - } - } - - // If we found nothing, return error. - if (!eventtable) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("valid events table not found"))); - - // Now that we've confirmed the RECOMMEND clause is well-formed, - // we can start assembling our structure. - attributes = getAttributeInfo(eventtable, userkey, itemkey, eventval, - recInfo); - recInfo->attributes = attributes; - - // That's all we need for now, really. - return recInfo; + char *usertref, *itemtref, *eventtref; + char *userkey, *itemkey, *eventval; + char *eventtable = NULL; + AttributeInfo *attributes; + bool elem_match = true; + + RecommendInfo *recInfo = (RecommendInfo*) recommendClause; + ColumnRef *usercr = (ColumnRef*) recInfo->userkey; + ColumnRef *itemcr = (ColumnRef*) recInfo->itemkey; + ColumnRef *eventcr = (ColumnRef*) recInfo->eventval; + + // First off, we'll perform sanity checks on the elements + // of the RECOMMEND clause. We need to make sure their + // table references are valid and matching. + userkey = getTableRef(usercr, &usertref); + itemkey = getTableRef(itemcr, &itemtref); + eventval = getTableRef(eventcr, &eventtref); + + // If one element has no table reference, none of them can have + // table references. + if ((usertref && !itemtref) || (!usertref && itemtref)) + elem_match = false; + if ((usertref && !eventtref) || (!usertref && eventtref)) + elem_match = false; + + // If table references exist, they all have to be the same. + if (usertref && elem_match) { + if ((strcmp(usertref,itemtref) != 0) || + (strcmp(usertref,eventtref) != 0)) + elem_match = false; + } + + if (!elem_match) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("elements of RECOMMEND clause must have matching table references"))); + + // Now that we've confirmed the correctness of the RECOMMEND + // clause table references, we will use them to find the event table + // referred to in the FROM clause. If there are table references, that makes + // the task easy; if not, then we can manually check to see if each column + // exists in a specific table. + if (usertref) { + // Let's look for a FROM table element that matches. + ListCell *from_cell; + foreach(from_cell,fromClause) { + Node *from_node = lfirst(from_cell); + if (nodeTag(from_node) == T_RangeVar) { + RangeVar *fromVar; + + fromVar = (RangeVar*) from_node; + if (tableMatch(fromVar,usertref)) { + eventtable = fromVar->relname; + //Use getRecommendVar to prevent circular linking while using copy functions + recInfo->recommender = getRecommendVar(fromVar); + fromVar->recommender = (Node*) recInfo; + break; + } + } + } + } else { + // If we can't easily identify the events table via + // table references, we will do so by cross-referencing the + // column names with the name of each table. + ListCell *from_cell; + foreach(from_cell,fromClause) { + Node *from_node = lfirst(from_cell); + if (nodeTag(from_node) == T_RangeVar) { + RangeVar *fromVar; + + fromVar = (RangeVar*) from_node; + // If all the key columns are in this table... + if (columnExistsInRelation(userkey,fromVar) && + columnExistsInRelation(itemkey,fromVar) && + columnExistsInRelation(eventval,fromVar)) { + // Did we already find a table matching all of + // these columns? If so, that's an error. + if (eventtable) { + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("ambiguous references in RECOMMEND clause"))); + } else { + // Make a note of the name, and also + // do cross-storage of the table. + eventtable = fromVar->relname; + //Use getRecommendVar to prevent circular linking while using copy functions + recInfo->recommender = getRecommendVar(fromVar); + fromVar->recommender = (Node*) recInfo; + } + } + } + } + } + + // If we found nothing, return error. + if (!eventtable) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("valid events table not found"))); + + // Now that we've confirmed the RECOMMEND clause is well-formed, + // we can start assembling our structure. + attributes = getAttributeInfo(eventtable, userkey, itemkey, eventval, + recInfo); + recInfo->attributes = attributes; + + // That's all we need for now, really. + return recInfo; } /* @@ -279,52 +303,52 @@ getEventsTable(List *fromClause, Node *recommendClause) { */ static char* getTableRef(ColumnRef *colref, char **colname) { - ListCell* col_cell; - Value* col_string; - int i; - - if (!colref) - return NULL; - - if (nodeTag(colref) != T_ColumnRef) { - (*colname) = NULL; - return NULL; - } - - // We take a look at the fields of the ColumnRef. - if (colref->fields->length < 1) { - (*colname) = NULL; - return NULL; - } - - col_cell = colref->fields->head; - // Random error condition: is this field not a string? - // I can't imagine where this would happen. - if (nodeTag(lfirst(col_cell)) != T_String) { - (*colname) = NULL; - return NULL; - } - - if (colref->fields->length < 2) { - (*colname) = NULL; - col_string = (Value*) lfirst(col_cell); - return col_string->val.str; - } - - // Depending on the number of fields, we need to continue - // on until we reach the final two. - for (i = 0; i+2 < colref->fields->length; i++) - col_cell = col_cell->next; - - // Extract the first string value (the table reference) - // and apply it. - col_string = (Value*) lfirst(col_cell); - (*colname) = col_string->val.str; - - // Now extract the actual column name and return it. - col_cell = col_cell->next; - col_string = (Value*) lfirst(col_cell); - return col_string->val.str; + ListCell* col_cell; + Value* col_string; + int i; + + if (!colref) + return NULL; + + if (nodeTag(colref) != T_ColumnRef) { + (*colname) = NULL; + return NULL; + } + + // We take a look at the fields of the ColumnRef. + if (colref->fields->length < 1) { + (*colname) = NULL; + return NULL; + } + + col_cell = colref->fields->head; + // Random error condition: is this field not a string? + // I can't imagine where this would happen. + if (nodeTag(lfirst(col_cell)) != T_String) { + (*colname) = NULL; + return NULL; + } + + if (colref->fields->length < 2) { + (*colname) = NULL; + col_string = (Value*) lfirst(col_cell); + return col_string->val.str; + } + + // Depending on the number of fields, we need to continue + // on until we reach the final two. + for (i = 0; i+2 < colref->fields->length; i++) + col_cell = col_cell->next; + + // Extract the first string value (the table reference) + // and apply it. + col_string = (Value*) lfirst(col_cell); + (*colname) = col_string->val.str; + + // Now extract the actual column name and return it. + col_cell = col_cell->next; + col_string = (Value*) lfirst(col_cell); + return col_string->val.str; } /* @@ -335,28 +359,28 @@ getTableRef(ColumnRef *colref, char **colname) { */ static AttributeInfo* getAttributeInfo(char *eventtable, char *userkey, char *itemkey, char *eventval, - RecommendInfo *recInfo) { - AttributeInfo* attributes = makeNode(AttributeInfo); - attributes->userID = -1; - attributes->recName = NULL; - attributes->usertable = NULL; - attributes->itemtable = NULL; - attributes->eventtable = eventtable; - attributes->userkey = userkey; - attributes->itemkey = itemkey; - attributes->eventval = eventval; - attributes->method = getRecMethod(recInfo->strmethod); - attributes->recIndexName = NULL; - attributes->recModelName = NULL; - attributes->recModelName2 = NULL; - attributes->recViewName = NULL; - attributes->userWhereClause = NULL; - attributes->IDfound = false; - attributes->cellType = CELL_ALPHA; - attributes->opType = recInfo->opType; - attributes->noFilter = false; - - return attributes; + RecommendInfo *recInfo) { + AttributeInfo* attributes = makeNode(AttributeInfo); + attributes->userID = -1; + attributes->recName = NULL; + attributes->usertable = NULL; + attributes->itemtable = NULL; + attributes->eventtable = eventtable; + attributes->userkey = userkey; + attributes->itemkey = itemkey; + attributes->eventval = eventval; + attributes->method = getRecMethod(recInfo->strmethod); + attributes->recIndexName = NULL; + attributes->recModelName = NULL; + attributes->recModelName2 = NULL; + attributes->recViewName = NULL; + attributes->userWhereClause = NULL; + attributes->IDfound = false; + attributes->cellType = CELL_ALPHA; + attributes->opType = recInfo->opType; + attributes->noFilter = false; + + return attributes; } /* @@ -367,13 +391,13 @@ getAttributeInfo(char *eventtable, char *userkey, char *itemkey, char *eventval, */ void addRecTargets(ParseState *pstate, List **targetlist, Node *recClause) { - RecommendInfo *recInfo = (RecommendInfo*) recClause; - - // Add the elements. Note that 3 corresponds to "RECOMMEND_CLAUSE" - // in parse_clause.c. - findTargetlistEntrySQL92(pstate, recInfo->userkey, targetlist, 3); - findTargetlistEntrySQL92(pstate, recInfo->itemkey, targetlist, 3); - findTargetlistEntrySQL92(pstate, recInfo->eventval, targetlist, 3); + RecommendInfo *recInfo = (RecommendInfo*) recClause; + + // Add the elements. Note that 3 corresponds to "RECOMMEND_CLAUSE" + // in parse_clause.c. + findTargetlistEntrySQL92(pstate, recInfo->userkey, targetlist, 3); + findTargetlistEntrySQL92(pstate, recInfo->itemkey, targetlist, 3); + findTargetlistEntrySQL92(pstate, recInfo->eventval, targetlist, 3); } /* @@ -384,66 +408,66 @@ addRecTargets(ParseState *pstate, List **targetlist, Node *recClause) { */ static int checkWhereClause(ColumnRef* attribute, RangeVar* recommender, char* userkey, char *eventval) { - List* attFields; - ListCell* att_cell; - - attFields = attribute->fields; - - // Like before, what we do depends on the length of this list. - switch (attFields->length) { - case 1: - // If there's only one element in the target, it needs - // to be the user ID or RecScore. - att_cell = attFields->head; - - if (nodeTag(lfirst(att_cell)) == T_String) { - Value* att_string = (Value*) lfirst(att_cell); - - // If the userID attribute is matched. - if (strcmp(att_string->val.str,userkey) == 0) - return 1; - // If the event value is matched. - if (strcmp(att_string->val.str,eventval) == 0) - return 2; - } - break; - case 2: - { - // If our target has two elements, then the first needs to - // refer to our recommender, and the second needs to be - // the user ID or eventval - bool go_on = false; - att_cell = attFields->head; - if (nodeTag(lfirst(att_cell)) == T_String) { - Value* att_string = (Value*) lfirst(att_cell); - if (recommender->alias == NULL) { - if (strcmp(att_string->val.str,recommender->relname) == 0) - go_on = true; - } else { - if ((strcmp(att_string->val.str,recommender->relname) == 0) || - (strcmp(att_string->val.str,recommender->alias->aliasname) == 0)) - go_on = true; - } - } - // If the first element does indeed match our recommender, go on. - if (go_on == true) { - att_cell = att_cell->next; - if (nodeTag(lfirst(att_cell)) == T_String) { - Value* att_string = (Value*) lfirst(att_cell); - // If the userID attribute is matched. - if (strcmp(att_string->val.str,userkey) == 0) - return 1; - // If the event value is matched. - if (strcmp(att_string->val.str,eventval) == 0) - return 2; - } - } - break; - } - default: - break; - } - return -1; + List* attFields; + ListCell* att_cell; + + attFields = attribute->fields; + + // Like before, what we do depends on the length of this list. + switch (attFields->length) { + case 1: + // If there's only one element in the target, it needs + // to be the user ID or RecScore. + att_cell = attFields->head; + + if (nodeTag(lfirst(att_cell)) == T_String) { + Value* att_string = (Value*) lfirst(att_cell); + + // If the userID attribute is matched. + if (strcmp(att_string->val.str,userkey) == 0) + return 1; + // If the event value is matched. + if (strcmp(att_string->val.str,eventval) == 0) + return 2; + } + break; + case 2: + { + // If our target has two elements, then the first needs to + // refer to our recommender, and the second needs to be + // the user ID or eventval + bool go_on = false; + att_cell = attFields->head; + if (nodeTag(lfirst(att_cell)) == T_String) { + Value* att_string = (Value*) lfirst(att_cell); + if (recommender->alias == NULL) { + if (strcmp(att_string->val.str,recommender->relname) == 0) + go_on = true; + } else { + if ((strcmp(att_string->val.str,recommender->relname) == 0) || + (strcmp(att_string->val.str,recommender->alias->aliasname) == 0)) + go_on = true; + } + } + // If the first element does indeed match our recommender, go on. + if (go_on == true) { + att_cell = att_cell->next; + if (nodeTag(lfirst(att_cell)) == T_String) { + Value* att_string = (Value*) lfirst(att_cell); + // If the userID attribute is matched. + if (strcmp(att_string->val.str,userkey) == 0) + return 1; + // If the event value is matched. + if (strcmp(att_string->val.str,eventval) == 0) + return 2; + } + } + break; + } + default: + break; + } + return -1; } /* @@ -453,43 +477,43 @@ checkWhereClause(ColumnRef* attribute, RangeVar* recommender, char* userkey, cha * CURRENTLY NOT IN USE. */ /*static void -modifyAExpr(Node *currentExpr, char* recname, char* viewname) { + modifyAExpr(Node *currentExpr, char* recname, char* viewname) { A_Expr *currentAExpr; - + if (!currentExpr) - return; - + return; + currentAExpr = (A_Expr*) currentExpr; // If our expression is an AND, recurse. if (currentAExpr->kind == AEXPR_AND) { - modifyAExpr(currentAExpr->lexpr,recname,viewname); - modifyAExpr(currentAExpr->rexpr,recname,viewname); + modifyAExpr(currentAExpr->lexpr,recname,viewname); + modifyAExpr(currentAExpr->rexpr,recname,viewname); } // If our expression is an =, then do the actual check. if (currentAExpr->kind == AEXPR_OP) { - // We need to check the left argument to see if it matches our recommender. - - // Left should be a recommender attribute. - if (nodeTag(currentAExpr->lexpr) == T_ColumnRef) - modifyColumnRef((ColumnRef*)currentAExpr->lexpr, recname, viewname); + // We need to check the left argument to see if it matches our recommender. + + // Left should be a recommender attribute. + if (nodeTag(currentAExpr->lexpr) == T_ColumnRef) + modifyColumnRef((ColumnRef*)currentAExpr->lexpr, recname, viewname); } -}*/ + }*/ -/* +/* * modifyTargetList - * Scan through the target list and replace one table name for another. * CURRENTLY NOT IN USE. */ /*static void -modifyTargetList(List *target_list, char *recname, char *viewname) { + modifyTargetList(List *target_list, char *recname, char *viewname) { ListCell *select_cell; - + foreach(select_cell,target_list) { - ResTarget* select_target = (ResTarget*) lfirst(select_cell); - ColumnRef* target_val = (ColumnRef*) select_target->val; - modifyColumnRef(target_val, recname, viewname); + ResTarget* select_target = (ResTarget*) lfirst(select_cell); + ColumnRef* target_val = (ColumnRef*) select_target->val; + modifyColumnRef(target_val, recname, viewname); } -}*/ + }*/ /* * modifyColumnRef - @@ -497,28 +521,28 @@ modifyTargetList(List *target_list, char *recname, char *viewname) { * CURRENTLY NOT IN USE. */ /*static void -modifyColumnRef(ColumnRef *attribute, char *recname, char *viewname) { + modifyColumnRef(ColumnRef *attribute, char *recname, char *viewname) { List* attFields = attribute->fields; ListCell* att_cell; // What we do depends on the length of this list. switch (attFields->length) { - case 2: - { - // If our target has two elements, then the first needs to - // refer to our recommender. If it's an alias, we won't need - // to change anything; if it's a direct reference to the name, - // we need to modify it. - att_cell = attFields->head; - if (nodeTag(lfirst(att_cell)) == T_String) { - Value* att_string = (Value*) lfirst(att_cell); - if (strcmp(att_string->val.str,recname) == 0) - att_string->val.str = viewname; - } - } - default: - break; + case 2: + { + // If our target has two elements, then the first needs to + // refer to our recommender. If it's an alias, we won't need + // to change anything; if it's a direct reference to the name, + // we need to modify it. + att_cell = attFields->head; + if (nodeTag(lfirst(att_cell)) == T_String) { + Value* att_string = (Value*) lfirst(att_cell); + if (strcmp(att_string->val.str,recname) == 0) + att_string->val.str = viewname; + } + } + default: + break; } -}*/ + }*/ /* * modifyFrom - @@ -529,127 +553,128 @@ modifyColumnRef(ColumnRef *attribute, char *recname, char *viewname) { */ static void modifyFrom(SelectStmt *stmt, RecommendInfo *recInfo) { - int i; -// char *eventtable; - char *query_string, *recindexname; - char *recmodelname, *recmodelname2, *recviewname; - recMethod method; - // Query information. - QueryDesc *queryDesc; - PlanState *planstate; - TupleTableSlot *slot; - MemoryContext recathoncontext; - - method = (recMethod) recInfo->attributes->method; - // We'll take a look to see if a recommender was already built - // on this table and method. - recindexname = retrieveRecommender(recInfo->attributes->eventtable,recInfo->strmethod); - - // If no recommender turned up, we'll just return right away. - // We'll utilize the events table for our event generation. Though - // we should note if this is a join table. - if (!recindexname) { - if (recInfo->opType == OP_JOIN) { - recInfo->opType = OP_GENERATEJOIN; - recInfo->attributes->opType = OP_GENERATEJOIN; - } - return; - } - - // We're using a different method from the default, which is - // OP_GENERATE. If we changed it to OP_JOIN, though, we'll - // leave it. - if (recInfo->opType == OP_GENERATE) { - recInfo->opType = OP_FILTER; - recInfo->attributes->opType = OP_FILTER; - } - - // If a recommender did turn up, then we need to track down the - // RecView and replace our event table with it. We'll also store - // the model table(s) for later use. - query_string = (char*) palloc(1024*sizeof(char)); - if (method == SVD) - sprintf(query_string,"select r.recusermodelname,r.recitemmodelname,r.recviewname from %s r;", - recindexname); - else - sprintf(query_string,"select r.recmodelname,r.recviewname from %s r;", - recindexname); - - // Now we prep the query. - queryDesc = recathon_queryStart(query_string, &recathoncontext); - planstate = queryDesc->planstate; - - // Now that we have a correct planstate, we can actually get information - // from the table. - slot = ExecProcNode(planstate); - if (TupIsNull(slot)) { - ereport(WARNING, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("recommender is built, but model could not be accessed. Building recommendation on the fly"))); - return; - } - - // Now we grab the appropriate information from the query tuple. - if (method == SVD) { - recmodelname = getTupleString(slot,"recusermodelname"); - recmodelname2 = getTupleString(slot,"recitemmodelname"); - } else { - recmodelname = getTupleString(slot,"recmodelname"); - recmodelname2 = NULL; - } - recviewname = getTupleString(slot,"recviewname"); - - // Now to tidy up. - recathon_queryEnd(queryDesc, recathoncontext); - pfree(query_string); - - // If we get to this point and there's no recmodelname, our query turned - // up no results, and something weird has gone wrong. I can't imagine a - // scenario where this is even possible, since the attributes we're trying - // to obtain are required to not be null, but it can't hurt. - if (recmodelname == NULL || recviewname == NULL) { - ereport(WARNING, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("recommender is built, but data could not be accessed. Building recommendation on the fly"))); - return; - } - - // Convert to lowercase. - for (i = 0; i < strlen(recindexname); i++) - recindexname[i] = tolower(recindexname[i]); - for (i = 0; i < strlen(recmodelname); i++) - recmodelname[i] = tolower(recmodelname[i]); - for (i = 0; i < strlen(recviewname); i++) - recviewname[i] = tolower(recviewname[i]); - if (recmodelname2) { - for (i = 0; i < strlen(recmodelname2); i++) - recmodelname2[i] = tolower(recmodelname2[i]); - } - - // Store the info, so we can use it later for the query. - recInfo->attributes->recIndexName = recindexname; - recInfo->attributes->recModelName = recmodelname; - recInfo->attributes->recModelName2 = recmodelname2; - recInfo->attributes->recViewName = recviewname; -// recInfo->attributes->recViewName = recInfo->attributes->eventtable; - - // When we do find the match, we need to replace our event table from the FROM clause - // with the recviewname we found. We also need to modify everything in the WHERE and - // RECOMMEND clauses if necessary, as well as the target list. At one point, we would - // try to add a condition to the WHERE clause to restrict the user ID, but since we're - // utilizing a custom scan operator, it's easier to do it manually at that stage. -// eventtable = recInfo->attributes->eventtable; -// modifyAExpr(stmt->whereClause,eventtable,recviewname); -// modifyTargetList(stmt->targetList,eventtable,recviewname); -// recInfo->recommender->relname = recviewname; - - // We need to store a pointer to this RecommendInfo struct in the RangeVar - // itself, because we'll be passing it on to future structures and eventually - // to the plan tree. Once we do this, we're done storing it in the recInfo, - // so we'll remove it to avoid the circular linking. That would be disastrous - // if copyObject were ever invoked. - recInfo->recommender->recommender = (Node*) recInfo; - recInfo->recommender = NULL; + int i; + // char *eventtable; + char *query_string, *recindexname; + char *recmodelname, *recmodelname2, *recviewname; + recMethod method; + // Query information. + QueryDesc *queryDesc; + PlanState *planstate; + TupleTableSlot *slot; + MemoryContext recathoncontext; + + method = (recMethod) recInfo->attributes->method; + // We'll take a look to see if a recommender was already built + // on this table and method. + recindexname = retrieveRecommender(recInfo->attributes->eventtable,recInfo->strmethod); + + // If no recommender turned up, we'll just return right away. + // We'll utilize the events table for our event generation. Though + // we should note if this is a join table. + if (!recindexname) { + if (recInfo->opType == OP_JOIN) { + recInfo->opType = OP_GENERATEJOIN; + recInfo->attributes->opType = OP_GENERATEJOIN; + } + return; + } + + // We're using a different method from the default, which is + // OP_GENERATE. If we changed it to OP_JOIN, though, we'll + // leave it. + if (recInfo->opType == OP_GENERATE) { + recInfo->opType = OP_FILTER; + recInfo->attributes->opType = OP_FILTER; + } + + // If a recommender did turn up, then we need to track down the + // RecView and replace our event table with it. We'll also store + // the model table(s) for later use. + query_string = (char*) palloc(1024*sizeof(char)); + if (method == SVD) + sprintf(query_string,"select r.recusermodelname,r.recitemmodelname,r.recviewname from %s r;", + recindexname); + else + sprintf(query_string,"select r.recmodelname,r.recviewname from %s r;", + recindexname); + + // Now we prep the query. + queryDesc = recathon_queryStart(query_string, &recathoncontext); + planstate = queryDesc->planstate; + + // Now that we have a correct planstate, we can actually get information + // from the table. + slot = ExecProcNode(planstate); + if (TupIsNull(slot)) { + ereport(WARNING, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("recommender is built, but model could not be accessed. Building recommendation on the fly"))); + return; + } + + // Now we grab the appropriate information from the query tuple. + if (method == SVD) { + recmodelname = getTupleString(slot,"recusermodelname"); + recmodelname2 = getTupleString(slot,"recitemmodelname"); + } else { + recmodelname = getTupleString(slot,"recmodelname"); + recmodelname2 = NULL; + } + recviewname = getTupleString(slot,"recviewname"); + + // Now to tidy up. + recathon_queryEnd(queryDesc, recathoncontext); + pfree(query_string); + + // If we get to this point and there's no recmodelname, our query turned + // up no results, and something weird has gone wrong. I can't imagine a + // scenario where this is even possible, since the attributes we're trying + // to obtain are required to not be null, but it can't hurt. + if (recmodelname == NULL || recviewname == NULL) { + ereport(WARNING, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("recommender is built, but data could not be accessed. Building recommendation on the fly"))); + return; + } + + // Convert to lowercase. + for (i = 0; i < strlen(recindexname); i++) + recindexname[i] = tolower(recindexname[i]); + for (i = 0; i < strlen(recmodelname); i++) + recmodelname[i] = tolower(recmodelname[i]); + for (i = 0; i < strlen(recviewname); i++) + recviewname[i] = tolower(recviewname[i]); + if (recmodelname2) { + for (i = 0; i < strlen(recmodelname2); i++) + recmodelname2[i] = tolower(recmodelname2[i]); + } + + // Store the info, so we can use it later for the query. + recInfo->attributes->recIndexName = recindexname; + recInfo->attributes->recModelName = recmodelname; + recInfo->attributes->recModelName2 = recmodelname2; + recInfo->attributes->recViewName = recviewname; + // recInfo->attributes->recViewName = recInfo->attributes->eventtable; + + // When we do find the match, we need to replace our event table from the FROM clause + // with the recviewname we found. We also need to modify everything in the WHERE and + // RECOMMEND clauses if necessary, as well as the target list. At one point, we would + // try to add a condition to the WHERE clause to restrict the user ID, but since we're + // utilizing a custom scan operator, it's easier to do it manually at that stage. + // eventtable = recInfo->attributes->eventtable; + // modifyAExpr(stmt->whereClause,eventtable,recviewname); + // modifyTargetList(stmt->targetList,eventtable,recviewname); + // recInfo->recommender->relname = recviewname; + + // We need to store a pointer to this RecommendInfo struct in the RangeVar + // itself, because we'll be passing it on to future structures and eventually + // to the plan tree. Once we do this, we're done storing it in the recInfo, + // so we'll remove it to avoid the circular linking. That would be disastrous + // if copyObject were ever invoked. + + //recInfo->recommender->recommender = (Node*) recInfo; + //recInfo->recommender = NULL; } /* @@ -661,8 +686,8 @@ modifyFrom(SelectStmt *stmt, RecommendInfo *recInfo) { */ static void filterfirst(Node *whereExpr, RecommendInfo *recInfo) { - if (filterfirstrecurse(whereExpr, recInfo)) - recInfo->attributes->noFilter = true; + if (filterfirstrecurse(whereExpr, recInfo)) + recInfo->attributes->noFilter = true; } /* @@ -674,32 +699,32 @@ filterfirst(Node *whereExpr, RecommendInfo *recInfo) { */ static bool filterfirstrecurse(Node *whereExpr, RecommendInfo *recInfo) { - if (!whereExpr) - return false; - - // If we've found a ColumnRef, then we check it to see if it - // matches RecScore for this (or all) recommenders. - if (nodeTag(whereExpr) == T_ColumnRef) { - int retvalue = checkWhereClause((ColumnRef*)whereExpr, recInfo->recommender, recInfo->attributes->userkey, recInfo->attributes->eventval); - - // 2 corresponds to "RecScore". - if (retvalue == 2) - return true; - else - return false; - } - - // If we've found an A_Expr, recurse on the left and right. We only - // need to find the RecScore in one place, so we "or" them together. - if (nodeTag(whereExpr) == T_A_Expr) { - A_Expr *whereAExpr = (A_Expr*) whereExpr; - - return filterfirstrecurse(whereAExpr->lexpr,recInfo) || - filterfirstrecurse(whereAExpr->rexpr,recInfo); - } - - // All other types fail, for now. - return false; + if (!whereExpr) + return false; + + // If we've found a ColumnRef, then we check it to see if it + // matches RecScore for this (or all) recommenders. + if (nodeTag(whereExpr) == T_ColumnRef) { + int retvalue = checkWhereClause((ColumnRef*)whereExpr, recInfo->recommender, recInfo->attributes->userkey, recInfo->attributes->eventval); + + // 2 corresponds to "RecScore". + if (retvalue == 2) + return true; + else + return false; + } + + // If we've found an A_Expr, recurse on the left and right. We only + // need to find the RecScore in one place, so we "or" them together. + if (nodeTag(whereExpr) == T_A_Expr) { + A_Expr *whereAExpr = (A_Expr*) whereExpr; + + return filterfirstrecurse(whereAExpr->lexpr,recInfo) || + filterfirstrecurse(whereAExpr->rexpr,recInfo); + } + + // All other types fail, for now. + return false; } /* @@ -708,27 +733,27 @@ filterfirstrecurse(Node *whereExpr, RecommendInfo *recInfo) { * CURRENTLY NOT IN USE. */ /*static void -applyRecJoin(Node *whereClause, List *fromClause, RecommendInfo *recInfo) { + applyRecJoin(Node *whereClause, List *fromClause, RecommendInfo *recInfo) { RangeVar *partnerTable; AttributeInfo *attributes = recInfo->attributes; RecommendInfo* partnerInfo; - + // It's only possible if we have multiple tables. if (list_length(fromClause) < 2) - return; - + return; + // Start by seeing if there's a match with the item key. partnerTable = locateJoinTable(whereClause, fromClause, - recInfo->recommender, attributes->itemkey); + recInfo->recommender, attributes->itemkey); // Then go to the user key. if (!partnerTable) - partnerTable = locateJoinTable(whereClause, fromClause, - recInfo->recommender, attributes->userkey); - + partnerTable = locateJoinTable(whereClause, fromClause, + recInfo->recommender, attributes->userkey); + // If we found no such table, give up. if (!partnerTable) - return; - + return; + // Otherwise, we found an appropriate table. Make a note. recInfo->opType = OP_JOIN; attributes->opType = OP_JOIN; @@ -736,7 +761,7 @@ applyRecJoin(Node *whereClause, List *fromClause, RecommendInfo *recInfo) { partnerInfo = makeNode(RecommendInfo); partnerInfo->opType = OP_JOINPARTNER; partnerTable->recommender = partnerInfo; -}*/ + }*/ /* @@ -747,106 +772,106 @@ applyRecJoin(Node *whereClause, List *fromClause, RecommendInfo *recInfo) { * CURRENTLY NOT IN USE. */ /*static RangeVar* -locateJoinTable(Node* recExpr, List *fromClause, RangeVar* eventtable, char* key) { + locateJoinTable(Node* recExpr, List *fromClause, RangeVar* eventtable, char* key) { A_Expr *recAExpr; - + if (!recExpr) - return NULL; - + return NULL; + // Turns out this isn't necessarily an A_Expr. if (nodeTag(recExpr) != T_A_Expr) - return NULL; - + return NULL; + recAExpr = (A_Expr*) recExpr; - + // If our expression is an =, then do the actual check. if (recAExpr->kind == AEXPR_OP) { - Value *opVal; - char *opType; - - // It is possible to have this odd error under some circumstances. - if (recAExpr->name->length == 0) - return NULL; - - opVal = (Value*) lfirst(recAExpr->name->head); - opType = opVal->val.str; - - if (strcmp(opType,"=") == 0) { - // We need to check the left and right arguments. - char *leftcol, *lefttable; - char *rightcol, *righttable; - - // Left should be a ColumnRef. If it is, extract the info. - // If we're dealing with the key in question, continue. - if (nodeTag(recAExpr->lexpr) == T_ColumnRef) { - ColumnRef *leftcr = (ColumnRef*) recAExpr->lexpr; - - leftcol = getTableRef(leftcr,&lefttable); - if (strcmp(leftcol,key) != 0) - return NULL; - } else - return NULL; - - // Right should be a ColumnRef too. If it is, extract the info. - // If we're dealing with the key in question, continue. - if (nodeTag(recAExpr->rexpr) == T_ColumnRef) { - ColumnRef *rightcr = (ColumnRef*) recAExpr->rexpr; - - rightcol = getTableRef(rightcr,&righttable); - if (strcmp(rightcol,key) != 0) - return NULL; - } else - return NULL; - - // If either table reference is null, just return NULL. That's - // not a valid WHERE clause anyway. - if (!lefttable || !righttable) - return NULL; - - // So we're dealing with two tables equating the key column. - // If one of the tables matches our ratings table, we will - // return the other one. - if (tableMatch(eventtable,lefttable)) { - ListCell *from_cell; - foreach(from_cell,fromClause) { - Node *from_node = lfirst(from_cell); - if (nodeTag(from_node) == T_RangeVar) { - RangeVar *fromVar; - - fromVar = (RangeVar*) from_node; - if (tableMatch(fromVar,righttable)) - return fromVar; - } - } - } - else if (tableMatch(eventtable,righttable)) { - ListCell *from_cell; - foreach(from_cell,fromClause) { - Node *from_node = lfirst(from_cell); - if (nodeTag(from_node) == T_RangeVar) { - RangeVar *fromVar; - - fromVar = (RangeVar*) from_node; - if (tableMatch(fromVar,lefttable)) - return fromVar; - } - } - } - } + Value *opVal; + char *opType; + + // It is possible to have this odd error under some circumstances. + if (recAExpr->name->length == 0) + return NULL; + + opVal = (Value*) lfirst(recAExpr->name->head); + opType = opVal->val.str; + + if (strcmp(opType,"=") == 0) { + // We need to check the left and right arguments. + char *leftcol, *lefttable; + char *rightcol, *righttable; + + // Left should be a ColumnRef. If it is, extract the info. + // If we're dealing with the key in question, continue. + if (nodeTag(recAExpr->lexpr) == T_ColumnRef) { + ColumnRef *leftcr = (ColumnRef*) recAExpr->lexpr; + + leftcol = getTableRef(leftcr,&lefttable); + if (strcmp(leftcol,key) != 0) + return NULL; + } else + return NULL; + + // Right should be a ColumnRef too. If it is, extract the info. + // If we're dealing with the key in question, continue. + if (nodeTag(recAExpr->rexpr) == T_ColumnRef) { + ColumnRef *rightcr = (ColumnRef*) recAExpr->rexpr; + + rightcol = getTableRef(rightcr,&righttable); + if (strcmp(rightcol,key) != 0) + return NULL; + } else + return NULL; + + // If either table reference is null, just return NULL. That's + // not a valid WHERE clause anyway. + if (!lefttable || !righttable) + return NULL; + + // So we're dealing with two tables equating the key column. + // If one of the tables matches our ratings table, we will + // return the other one. + if (tableMatch(eventtable,lefttable)) { + ListCell *from_cell; + foreach(from_cell,fromClause) { + Node *from_node = lfirst(from_cell); + if (nodeTag(from_node) == T_RangeVar) { + RangeVar *fromVar; + + fromVar = (RangeVar*) from_node; + if (tableMatch(fromVar,righttable)) + return fromVar; + } + } + } + else if (tableMatch(eventtable,righttable)) { + ListCell *from_cell; + foreach(from_cell,fromClause) { + Node *from_node = lfirst(from_cell); + if (nodeTag(from_node) == T_RangeVar) { + RangeVar *fromVar; + + fromVar = (RangeVar*) from_node; + if (tableMatch(fromVar,lefttable)) + return fromVar; + } + } + } + } } // If we didn't find what we're looking for, recurse. else { - RangeVar *rtnvar; - - rtnvar = locateJoinTable(recAExpr->lexpr,fromClause,eventtable,key); - if (rtnvar) return rtnvar; - rtnvar = locateJoinTable(recAExpr->rexpr,fromClause,eventtable,key); - if (rtnvar) return rtnvar; + RangeVar *rtnvar; + + rtnvar = locateJoinTable(recAExpr->lexpr,fromClause,eventtable,key); + if (rtnvar) return rtnvar; + rtnvar = locateJoinTable(recAExpr->rexpr,fromClause,eventtable,key); + if (rtnvar) return rtnvar; } - + // All other kinds fail, at least for now. return NULL; -}*/ + }*/ /* * tableMatch - @@ -855,17 +880,17 @@ locateJoinTable(Node* recExpr, List *fromClause, RangeVar* eventtable, char* key */ static bool tableMatch(RangeVar* table, char* tablename) { - if (table->alias) { - if (strcmp(table->alias->aliasname,tablename) == 0) { - return true; - } - } else { - if (strcmp(table->relname,tablename) == 0) { - return true; - } - } - - return false; + if (table->alias) { + if (strcmp(table->alias->aliasname,tablename) == 0) { + return true; + } + } else { + if (strcmp(table->relname,tablename) == 0) { + return true; + } + } + + return false; } /* @@ -875,20 +900,20 @@ tableMatch(RangeVar* table, char* tablename) { */ static Node* makeTrueConst() { - A_Const *n; - TypeCast *tc; - - n = makeNode(A_Const); - n->val.type = T_String; - n->val.val.str = "t"; - n->location = -1; - - tc = makeNode(TypeCast); - tc->arg = (Node *) n; - tc->typeName = SystemTypeName("bool"); - tc->location = -1; - - return (Node *) tc; + A_Const *n; + TypeCast *tc; + + n = makeNode(A_Const); + n->val.type = T_String; + n->val.val.str = "t"; + n->location = -1; + + tc = makeNode(TypeCast); + tc->arg = (Node *) n; + tc->typeName = SystemTypeName("bool"); + tc->location = -1; + + return (Node *) tc; } /* @@ -900,176 +925,176 @@ makeTrueConst() { */ static int userWhereOp(Node* whereClause, char *userkey) { - A_Expr *recAExpr; - int leftresult = 0, rightresult = 0; - - if (!whereClause) - return 0; - - recAExpr = (A_Expr*) whereClause; - - // If our expression is an OP or IN, then do the actual check. - if (recAExpr->kind == AEXPR_OP || recAExpr->kind == AEXPR_IN) { - char *leftcol, *lefttable; - char *rightcol, *righttable; - bool leftiscol = false, rightiscol = false, userfound = false; - bool leftaexpr = false, rightaexpr = false; - - // It is possible to have this odd error under some circumstances. - if (recAExpr->name->length == 0) - return 0; - - // If the left column is our user key column, that's a good sign. - // Let's just hope we're not joining with some other column. - if (recAExpr->lexpr && nodeTag(recAExpr->lexpr) == T_ColumnRef) { - ColumnRef *leftcr = (ColumnRef*) recAExpr->lexpr; - - leftiscol = true; - leftcol = getTableRef(leftcr,&lefttable); - if (strcmp(leftcol,userkey) == 0) - userfound = true; - } - - // If the right column is our user key column, return right away. - if (recAExpr->rexpr && nodeTag(recAExpr->rexpr) == T_ColumnRef) { - ColumnRef *rightcr = (ColumnRef*) recAExpr->rexpr; - - rightiscol = true; - rightcol = getTableRef(rightcr,&righttable); - if (strcmp(rightcol,userkey) == 0) - userfound = true; - } - - // If this OP/IN doesn't involve the user key at all, then we'll - // replace it with a TRUE boolean constant. Likewise, if we're - // equating it with some other column, that's not useful to us, - // so we'll again replace it with a TRUE constant. - if (leftiscol && rightiscol) - return -1; - else if (!leftiscol && !rightiscol) - return 0; - - // If this OP has more A_Exprs under it, we need to recurse and - // see what's in them. - if (recAExpr->lexpr && nodeTag(recAExpr->lexpr) == T_A_Expr) { - leftaexpr = true; - leftresult = userWhereOp(recAExpr->lexpr,userkey); - } - if (recAExpr->rexpr && nodeTag(recAExpr->rexpr) == T_A_Expr) { - rightaexpr = true; - rightresult = userWhereOp(recAExpr->rexpr, userkey); - } - - // Any AExprs? - if (leftaexpr || rightaexpr) { - // If we found another column anywhere, the whole thing is - // useless. - if (leftresult < 0 || rightresult < 0) - return -1; - - // If we didn't find the user column, it's similarly useless. - if (leftresult == 0 && rightresult == 0) - return 0; - - // Otherwise, if we found the user key, we can use this item. - if (userfound) { - return 1; - } - else - return 0; - } - } - // If our expression is an OP or IN, then do the actual check. - if (recAExpr->kind == AEXPR_OP || recAExpr->kind == AEXPR_IN) { - char *leftcol, *lefttable; - char *rightcol, *righttable; - bool leftiscol = false, rightiscol = false, userfound = false; - bool leftaexpr = false, rightaexpr = false; - - // It is possible to have this odd error under some circumstances. - if (recAExpr->name->length == 0) - return 0; - - // If this OP has more A_Exprs under it, we need to recurse and - // see what's in them. - if (recAExpr->lexpr && nodeTag(recAExpr->lexpr) == T_A_Expr) { - leftaexpr = true; - leftresult = userWhereOp(recAExpr->lexpr,userkey); - } - if (recAExpr->rexpr && nodeTag(recAExpr->rexpr) == T_A_Expr) { - rightaexpr = true; - rightresult = userWhereOp(recAExpr->rexpr, userkey); - } - - // Any AExprs? - if (leftaexpr || rightaexpr) { - // If we found another column anywhere, the whole thing is - // useless. - if (leftresult < 0 || rightresult < 0) - return -1; - - // If we found the user column, though, make a note. - if (leftresult == 1 || rightresult == 1) - userfound = true; - } - - // If at least one isn't an A_Expr, then we check to see if either - // is a ColumnRef. - - // If the left column is our user key column, that's a good sign. - // Let's just hope we're not joining with some other column. - if (recAExpr->lexpr && nodeTag(recAExpr->lexpr) == T_ColumnRef) { - ColumnRef *leftcr = (ColumnRef*) recAExpr->lexpr; - - leftiscol = true; - leftcol = getTableRef(leftcr,&lefttable); - - if (strcmp(leftcol,userkey) == 0) - userfound = true; - else - return -1; - } - - // If the right column is our user key column, return right away. - if (recAExpr->rexpr && nodeTag(recAExpr->rexpr) == T_ColumnRef) { - ColumnRef *rightcr = (ColumnRef*) recAExpr->rexpr; - - rightiscol = true; - rightcol = getTableRef(rightcr,&righttable); - - if (strcmp(rightcol,userkey) == 0) - userfound = true; - else - return -1; - } - - // If both items are columns, that can't possibly be good. - if (leftiscol && rightiscol) - return 0; - - // Otherwise, if we found the user key, we can use this item. - if (userfound) - return 1; - else - return 0; - } - // Recurse in a similar manner if this is an AND/OR/NOT. - else if (recAExpr->kind == AEXPR_AND || recAExpr->kind == AEXPR_OR) { - leftresult = userWhereOp(recAExpr->lexpr,userkey); - rightresult = userWhereOp(recAExpr->rexpr,userkey); - - if (leftresult < 0 || rightresult < 0) - return -1; - else if (leftresult == 0 && rightresult == 0) - return 0; - else - return 1; - } else if (recAExpr->kind == AEXPR_NOT) { - return userWhereOp(recAExpr->rexpr,userkey); - } - - // Return 0 by default. - return 0; + A_Expr *recAExpr; + int leftresult = 0, rightresult = 0; + + if (!whereClause) + return 0; + + recAExpr = (A_Expr*) whereClause; + + // If our expression is an OP or IN, then do the actual check. + if (recAExpr->kind == AEXPR_OP || recAExpr->kind == AEXPR_IN) { + char *leftcol, *lefttable; + char *rightcol, *righttable; + bool leftiscol = false, rightiscol = false, userfound = false; + bool leftaexpr = false, rightaexpr = false; + + // It is possible to have this odd error under some circumstances. + if (recAExpr->name->length == 0) + return 0; + + // If the left column is our user key column, that's a good sign. + // Let's just hope we're not joining with some other column. + if (recAExpr->lexpr && nodeTag(recAExpr->lexpr) == T_ColumnRef) { + ColumnRef *leftcr = (ColumnRef*) recAExpr->lexpr; + + leftiscol = true; + leftcol = getTableRef(leftcr,&lefttable); + if (strcmp(leftcol,userkey) == 0) + userfound = true; + } + + // If the right column is our user key column, return right away. + if (recAExpr->rexpr && nodeTag(recAExpr->rexpr) == T_ColumnRef) { + ColumnRef *rightcr = (ColumnRef*) recAExpr->rexpr; + + rightiscol = true; + rightcol = getTableRef(rightcr,&righttable); + if (strcmp(rightcol,userkey) == 0) + userfound = true; + } + + // If this OP/IN doesn't involve the user key at all, then we'll + // replace it with a TRUE boolean constant. Likewise, if we're + // equating it with some other column, that's not useful to us, + // so we'll again replace it with a TRUE constant. + if (leftiscol && rightiscol) + return -1; + else if (!leftiscol && !rightiscol) + return 0; + + // If this OP has more A_Exprs under it, we need to recurse and + // see what's in them. + if (recAExpr->lexpr && nodeTag(recAExpr->lexpr) == T_A_Expr) { + leftaexpr = true; + leftresult = userWhereOp(recAExpr->lexpr,userkey); + } + if (recAExpr->rexpr && nodeTag(recAExpr->rexpr) == T_A_Expr) { + rightaexpr = true; + rightresult = userWhereOp(recAExpr->rexpr, userkey); + } + + // Any AExprs? + if (leftaexpr || rightaexpr) { + // If we found another column anywhere, the whole thing is + // useless. + if (leftresult < 0 || rightresult < 0) + return -1; + + // If we didn't find the user column, it's similarly useless. + if (leftresult == 0 && rightresult == 0) + return 0; + + // Otherwise, if we found the user key, we can use this item. + if (userfound) { + return 1; + } + else + return 0; + } + } + // If our expression is an OP or IN, then do the actual check. + if (recAExpr->kind == AEXPR_OP || recAExpr->kind == AEXPR_IN) { + char *leftcol, *lefttable; + char *rightcol, *righttable; + bool leftiscol = false, rightiscol = false, userfound = false; + bool leftaexpr = false, rightaexpr = false; + + // It is possible to have this odd error under some circumstances. + if (recAExpr->name->length == 0) + return 0; + + // If this OP has more A_Exprs under it, we need to recurse and + // see what's in them. + if (recAExpr->lexpr && nodeTag(recAExpr->lexpr) == T_A_Expr) { + leftaexpr = true; + leftresult = userWhereOp(recAExpr->lexpr,userkey); + } + if (recAExpr->rexpr && nodeTag(recAExpr->rexpr) == T_A_Expr) { + rightaexpr = true; + rightresult = userWhereOp(recAExpr->rexpr, userkey); + } + + // Any AExprs? + if (leftaexpr || rightaexpr) { + // If we found another column anywhere, the whole thing is + // useless. + if (leftresult < 0 || rightresult < 0) + return -1; + + // If we found the user column, though, make a note. + if (leftresult == 1 || rightresult == 1) + userfound = true; + } + + // If at least one isn't an A_Expr, then we check to see if either + // is a ColumnRef. + + // If the left column is our user key column, that's a good sign. + // Let's just hope we're not joining with some other column. + if (recAExpr->lexpr && nodeTag(recAExpr->lexpr) == T_ColumnRef) { + ColumnRef *leftcr = (ColumnRef*) recAExpr->lexpr; + + leftiscol = true; + leftcol = getTableRef(leftcr,&lefttable); + + if (strcmp(leftcol,userkey) == 0) + userfound = true; + else + return -1; + } + + // If the right column is our user key column, return right away. + if (recAExpr->rexpr && nodeTag(recAExpr->rexpr) == T_ColumnRef) { + ColumnRef *rightcr = (ColumnRef*) recAExpr->rexpr; + + rightiscol = true; + rightcol = getTableRef(rightcr,&righttable); + + if (strcmp(rightcol,userkey) == 0) + userfound = true; + else + return -1; + } + + // If both items are columns, that can't possibly be good. + if (leftiscol && rightiscol) + return 0; + + // Otherwise, if we found the user key, we can use this item. + if (userfound) + return 1; + else + return 0; + } + // Recurse in a similar manner if this is an AND/OR/NOT. + else if (recAExpr->kind == AEXPR_AND || recAExpr->kind == AEXPR_OR) { + leftresult = userWhereOp(recAExpr->lexpr,userkey); + rightresult = userWhereOp(recAExpr->rexpr,userkey); + + if (leftresult < 0 || rightresult < 0) + return -1; + else if (leftresult == 0 && rightresult == 0) + return 0; + else + return 1; + } else if (recAExpr->kind == AEXPR_NOT) { + return userWhereOp(recAExpr->rexpr,userkey); + } + + // Return 0 by default. + return 0; } /* @@ -1083,102 +1108,106 @@ userWhereOp(Node* whereClause, char *userkey) { */ static Node* userWhereClause(Node* whereClause, char *userkey) { - A_Expr *recAExpr; - - if (!whereClause) - return NULL; - - // Turns out this isn't necessarily an A_Expr. - if (nodeTag(whereClause) != T_A_Expr) - return NULL; - - recAExpr = (A_Expr*) whereClause; - - // If our expression is an OP or IN, then do the actual check. - if (recAExpr->kind == AEXPR_OP || recAExpr->kind == AEXPR_IN) { - char *leftcol, *lefttable; - char *rightcol, *righttable; - bool leftiscol = false, rightiscol = false, userfound = false; - bool leftaexpr = false, rightaexpr = false; - int leftresult = 0, rightresult = 0; - - // It is possible to have this odd error under some circumstances. - if (recAExpr->name->length == 0) - return NULL; - - // If this OP has more A_Exprs under it, we need to recurse and - // see what's in them. - if (recAExpr->lexpr && nodeTag(recAExpr->lexpr) == T_A_Expr) { - leftaexpr = true; - leftresult = userWhereOp(recAExpr->lexpr,userkey); - } - if (recAExpr->rexpr && nodeTag(recAExpr->rexpr) == T_A_Expr) { - rightaexpr = true; - rightresult = userWhereOp(recAExpr->rexpr, userkey); - } - - // Any AExprs? - if (leftaexpr || rightaexpr) { - // If we found another column anywhere, the whole thing is - // useless. - if (leftresult < 0 || rightresult < 0) - return makeTrueConst(); - - // If we found the user column, though, make a note. - if (leftresult == 1 || rightresult == 1) - userfound = true; - } - - // If at least one isn't an A_Expr, then we check to see if either - // is a ColumnRef. - - // If the left column is our user key column, that's a good sign. - // Let's just hope we're not joining with some other column. - if (recAExpr->lexpr && nodeTag(recAExpr->lexpr) == T_ColumnRef) { - ColumnRef *leftcr = (ColumnRef*) recAExpr->lexpr; - - leftiscol = true; - leftcol = getTableRef(leftcr,&lefttable); - - if (strcmp(leftcol,userkey) == 0) - userfound = true; - else - return makeTrueConst(); - } - - // If the right column is our user key column, return right away. - if (recAExpr->rexpr && nodeTag(recAExpr->rexpr) == T_ColumnRef) { - ColumnRef *rightcr = (ColumnRef*) recAExpr->rexpr; - - rightiscol = true; - rightcol = getTableRef(rightcr,&righttable); - - if (strcmp(rightcol,userkey) == 0) - userfound = true; - else - return makeTrueConst(); - } - - // If both items are columns, that can't possibly be good. - if (leftiscol && rightiscol) - return makeTrueConst(); - - // Otherwise, if we found the user key, we can use this item. - if (userfound) - return (Node *) recAExpr; - else - return makeTrueConst(); - } - // Recurse if this is an AND/OR/NOT. - else if (recAExpr->kind == AEXPR_AND || recAExpr->kind == AEXPR_OR) { - recAExpr->lexpr = userWhereClause(recAExpr->lexpr,userkey); - recAExpr->rexpr = userWhereClause(recAExpr->rexpr,userkey); - } else if (recAExpr->kind == AEXPR_NOT) { - recAExpr->rexpr = userWhereClause(recAExpr->rexpr,userkey); - } - - // Return the expression. - return (Node *) recAExpr; + A_Expr *recAExpr; + + if (!whereClause) + return NULL; + + // Turns out this isn't necessarily an A_Expr. POSTGIS Support + if (nodeTag(whereClause) == T_FuncCall) + return makeTrueConst(); + + if (nodeTag(whereClause) != T_A_Expr) + return NULL; + + recAExpr = (A_Expr*) whereClause; + + // If our expression is an OP or IN, then do the actual check. + if (recAExpr->kind == AEXPR_OP || recAExpr->kind == AEXPR_IN) { + char *leftcol, *lefttable; + char *rightcol, *righttable; + bool leftiscol = false, rightiscol = false, userfound = false; + bool leftaexpr = false, rightaexpr = false; + int leftresult = 0, rightresult = 0; + + // It is possible to have this odd error under some circumstances. + if (recAExpr->name->length == 0) + return NULL; + + // If this OP has more A_Exprs under it, we need to recurse and + // see what's in them. + if (recAExpr->lexpr && nodeTag(recAExpr->lexpr) == T_A_Expr) { + leftaexpr = true; + leftresult = userWhereOp(recAExpr->lexpr,userkey); + } + if (recAExpr->rexpr && nodeTag(recAExpr->rexpr) == T_A_Expr) { + rightaexpr = true; + rightresult = userWhereOp(recAExpr->rexpr, userkey); + } + + // Any AExprs? + if (leftaexpr || rightaexpr) { + // If we found another column anywhere, the whole thing is + // useless. + if (leftresult < 0 || rightresult < 0) + return makeTrueConst(); + + // If we found the user column, though, make a note. + if (leftresult == 1 || rightresult == 1) + userfound = true; + } + + // If at least one isn't an A_Expr, then we check to see if either + // is a ColumnRef. + + // If the left column is our user key column, that's a good sign. + // Let's just hope we're not joining with some other column. + if (recAExpr->lexpr && nodeTag(recAExpr->lexpr) == T_ColumnRef) { + ColumnRef *leftcr = (ColumnRef*) recAExpr->lexpr; + + leftiscol = true; + leftcol = getTableRef(leftcr,&lefttable); + + if (strcmp(leftcol,userkey) == 0) + userfound = true; + else + return makeTrueConst(); + } + + // If the right column is our user key column, return right away. + if (recAExpr->rexpr && nodeTag(recAExpr->rexpr) == T_ColumnRef) { + ColumnRef *rightcr = (ColumnRef*) recAExpr->rexpr; + + rightiscol = true; + rightcol = getTableRef(rightcr,&righttable); + + if (strcmp(rightcol,userkey) == 0) + userfound = true; + else + return makeTrueConst(); + } + + // If both items are columns, that can't possibly be good. + if (leftiscol && rightiscol) + return makeTrueConst(); + + // Otherwise, if we found the user key, we can use this item. + if (userfound) + return (Node *) recAExpr; + else + return makeTrueConst(); + } + // Recurse if this is an AND/OR/NOT. + else if (recAExpr->kind == AEXPR_AND || recAExpr->kind == AEXPR_OR) { + recAExpr->lexpr = userWhereClause(recAExpr->lexpr,userkey); + recAExpr->rexpr = userWhereClause(recAExpr->rexpr,userkey); + } else if (recAExpr->kind == AEXPR_NOT) { + recAExpr->rexpr = userWhereClause(recAExpr->rexpr,userkey); + } + + + // Return the expression. + return (Node *) recAExpr; } /* @@ -1187,17 +1216,19 @@ userWhereClause(Node* whereClause, char *userkey) { */ void userWhereTransform(ParseState *pstate, Node* recommendClause) { - RecommendInfo *recInfo; - Node *userWhere; - - if (!recommendClause) - return; - - recInfo = (RecommendInfo*) recommendClause; - userWhere = recInfo->attributes->userWhereClause; - if (userWhere) { - userWhere = transformExpr(pstate, userWhere); - userWhere = coerce_to_boolean(pstate, userWhere, "USER_WHERE"); - } - recInfo->attributes->userWhereClause = userWhere; + RecommendInfo *recInfo; + Node *userWhere; + + if (!recommendClause) + return; + + recInfo = (RecommendInfo*) recommendClause; + userWhere = recInfo->attributes->userWhereClause; + if (userWhere) { + userWhere = transformExpr(pstate, userWhere); + userWhere = coerce_to_boolean(pstate, userWhere, "USER_WHERE"); + } + recInfo->attributes->userWhereClause = userWhere; + //debug + //printf("type of att userwhere: %u\n", userWhere->type); } diff --git a/PostgreSQL/src/backend/utils/misc/recathon.c b/PostgreSQL/src/backend/utils/misc/recathon.c index bfe1abe..477f639 100644 --- a/PostgreSQL/src/backend/utils/misc/recathon.c +++ b/PostgreSQL/src/backend/utils/misc/recathon.c @@ -4500,6 +4500,7 @@ applyItemSim(RecScanState *recnode, char *itemmodel) ratedTable = recnode->ratedTable; + querystring = (char*) palloc(1024*sizeof(char)); // For every item we've rated, we need to obtain its similarity diff --git a/README.md b/README.md index baf086f..ebcc2b8 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Welcome to RecDB RecDB is an Open Source Recommendation Engine Built Entirely Inside PostgreSQL 9.2. RecDB allows application developers to build recommendation applications in a heartbeat through a wide variety of built-in recommendation algorithms like user-user collaborative filtering, item-item collaborative filtering, singular value decomposition. Applications powered by RecDB can produce online and flexible personalized recommendations to end-users. -![RecDB Logo](http://www-users.cs.umn.edu/~sarwat/RecDB/pics/recdblogo.png) current version: ```v0.2-alpha``` +![RecDB Logo](8F51D3FB-A4C0-4236-8598-A084DCDBCF9D.jpeg) current version: ```v1.1``` ## How to Get Source Code @@ -148,6 +148,10 @@ LIMIT 10 ## Publications +* [Database System Support for Personalized Recommendation Applications](http://ieeexplore.ieee.org/document/7930070/) +Mohamed Sarwat, Raha Moraffah, Mohamed F. Mokbel, James L. Avery. +Proceedings of the IEEE International Conference on Data Engineering, ICDE 2017: 1320-1331 + * [Recdb in Action: Recommendation Made Easy in Relational Databases](http://dl.acm.org/citation.cfm?id=2536286). Mohamed Sarwat, James L. Avery, Mohamed F. Mokbel. Proceedings of the Very Large Databases Endowment, PVLDB 6 (12), 1242-1245, 2013 diff --git a/examples/MoiveLens/script2.py b/examples/MoiveLens/script2.py new file mode 100644 index 0000000..bae3c76 --- /dev/null +++ b/examples/MoiveLens/script2.py @@ -0,0 +1,217 @@ +####Movie Lens 1m### +#Tests for fixed bugs (Explain, Explain Analyze, ..)# + + +import psycopg2 +import sys +import time +import os +def main(): + host = raw_input("Enter the host address of postgresql: ") + + dbname = raw_input("Enter the database name: ") + + user = raw_input("Enter the username of postgresql: ") + + password = raw_input("Enter the password of postgresql: ") + + #First data set + UserDataPath = raw_input("Enter the abs path for the first set of user data(.dat file): ") + + ItemDataPath = raw_input("Enter the abs path for the first set of item data(.dat file): ") + + RatingDataPath = raw_input("Enter the abs path for the first set of ratings data(.dat file): ") + + #Second recommender data set path + + RatingDataPath2 = raw_input("Enter the abs path for the MoiveTweets ratings data(.csv file): ") + + + #Define our connection string + conn_string = "host='"+host+"' dbname='"+dbname+"' user='"+user+"' password='"+password+"'" + + # print the connection string we will use to connect + print "Connecting to database\n ->%s" % (conn_string) + + # get a connection, if a connect cannot be made an exception will be raised here + conn = psycopg2.connect(conn_string) + cursor = conn.cursor() + + print "Data copying from .csv file to postgresql database" + + import os + path = os.getcwd() + + executionStart = time.time() + + cursor.execute(" set client_encoding = LATIN1;"); + conn.commit() + + cursor.execute("create table if not exists users( userid int, age varchar, gender varchar, job varchar, zipcode varchar);"); + conn.commit() + executionTime = time.time() - executionStart + print "\n Execution time is :-" + print executionTime + + executionStart = time.time() + query = "COPY users(userid,gender,age,job,zipcode) from "+UserDataPath+"DELIMITERS ';';" + cursor.execute(query); + conn.commit() + executionTime = time.time() - executionStart + print "\n Execution time is :-" + print executionTime + + cursor.execute("create table if not exists moive( itemid int, name varchar, genre varchar);"); + conn.commit() + + query = "COPY moive(itemid,name,genre) from "+ItemDataPath+" DELIMITERS ';';" + cursor.execute(query); + conn.commit() + + + cursor.execute("create table if not exists ratings ( userid int, itemid int, rating real ,garbage varchar);"); + conn.commit() + + query = "COPY ratings(userid,itemid,rating,garbage) from "+RatingDataPath+" DELIMITERS ';';" + cursor.execute(query); + conn.commit() + + #Second recommender informations + cursor.execute("create table if not exists gsratings (userid int, itemid int, rating int);"); + conn.commit() + executionTime = time.time() - executionStart + + query = "copy gsratings(userid, itemid, rating) from "+RatingDataPath2+" DELIMITER ':';" + cursor.execute(query); + conn.commit() + + + + + print "Connected!\n" + + ############### + print "\n \n Creating Recommender for join of two recommendation queries.." + executionStart = time.time() + cursor.execute("CREATE RECOMMENDER mtitemcos on gsratings Users FROM userid Items FROM itemid Events FROM rating Using ItemCosCF;"); + conn.commit() + executionTime = time.time() - executionStart + print "\n" + print (" Execution time is :-", executionTime) + + + ############### + + print "Recommendation query being shooted with ItemCosCF technique" + + ############### + + print "\n \n Creating Recommender.." + executionStart = time.time() + cursor.execute("CREATE RECOMMENDER mlRecItemCos on ratings Users FROM userid Items FROM itemid Events FROM rating Using ItemCosCF;"); + conn.commit() + executionTime = time.time() - executionStart + print " Execution time is :-" + print executionTime + + ############### + + print "\n \n Explain the selection of movie for single user.." + executionStart = time.time() + cursor.execute("explain select itemid from ratings RECOMMEND itemid to userid ON rating Using ItemCosCF where userid =21;"); + conn.commit() + executionTime = time.time() - executionStart + print " Execution time is :-" + print executionTime + + ############### + + print "\n \n Explain Analyze for the selection of movie for single user.." + executionStart = time.time() + cursor.execute("explain analyze select itemid from ratings RECOMMEND itemid to userid ON rating Using ItemCosCF where userid =21;"); + conn.commit() + executionTime = time.time() - executionStart + print " Execution time is :-" + print executionTime + + ################ + + print "\n \n Explain the Join Query.." + executionStart = time.time() + cursor.execute("explain select r.itemid, i.name, i,genre, r.rating , r.userid, b.age from ratings r, moive i, users b Recommend r.itemid to r.userid On r.rating Using ItemCosCF where r.userid = 1 and r.userid = b.userid and r.itemid = i.itemid AND i.genre ILIKE '%action%' ;"); + conn.commit() + executionTime = time.time() - executionStart + print " Execution time is :-" + print executionTime + + ################ + + print "\n \n Explain Analyze the Join Query.." + executionStart = time.time() + cursor.execute("explain analyze select r.itemid, i.name, i,genre, r.rating , r.userid, b.age from ratings r, moive i, users b Recommend r.itemid to r.userid On r.rating Using ItemCosCF where r.userid = 1 and r.userid = b.userid and r.itemid = i.itemid AND i.genre ILIKE '%action%' ;"); + conn.commit() + executionTime = time.time() - executionStart + print " Execution time is :-" + print executionTime + + + + ################ + + print "\n \n Join of Two Recommendations.." + executionStart = time.time() + cursor.execute("select t1.itemid, t1.userid, t2.itemid, t2.userid FROM (select * from ratings r Recommend r.itemid TO r.userid ON r.rating USING ItemCosCF where r.userid =15 limit 10) t1 join (select * from gsratings g RECOMMEND g.itemid TO g.userid ON g.rating USING ItemCosCF where g.userid between 10 and 20 AND g.itemid between 90000 and 100000) t2 ON t1.userid =t2.userid limit 10;"); + conn.commit() + executionTime = time.time() - executionStart + print " Execution time is :-" + print executionTime + + ############### + + print "\n \n Union of Two Recommendations.." + executionStart = time.time() + cursor.execute("(select r.userid from ratings r RECOMMEND r.itemid TO r.userid ON r.rating USING ItemCosCF where r.userid =1 ) union (select g.userid from gsratings g RECOMMEND g.itemid TO g.userid ON g.rating USING ItemCosCF where g.userid =21);"); + conn.commit() + executionTime = time.time() - executionStart + print "Execution time is :-" + print executionTime + + ############### + + print "\n \n Recommender in subselect" + executionStart = time.time() + cursor.execute("select u.age, sub.rating from users u, (select * FROM ratings r RECOMMEND r.itemid TO r.userid ON r.rating USING ItemCosCF WHERE r.itemid in (1,2,3) limit 10) sub WHERE u.userid = sub.userid;"); + conn.commit() + executionTime = time.time() - executionStart + print " Execution time is :-" + print executionTime + + ############### + + print "\n \n Recommender and IN" + executionStart = time.time() + cursor.execute("select * from moive m where m.itemid IN (SELECT r.itemid FROM ratings r RECOMMEND r.itemid TO r.userid ON r.rating USING ItemCosCF WHERE r.userid=1 limit 10);"); + conn.commit() + executionTime = time.time() - executionStart + print " Execution time is :-" + print executionTime + + ################ + + cursor.execute("drop table ratings;"); + conn.commit() + + cursor.execute("drop table users;"); + conn.commit() + + cursor.execute("drop table moive;"); + conn.commit() + + cursor.execute("drop table gsratings;"); + conn.commit() + + + + +if __name__ == "__main__": + main() diff --git a/examples/README.md b/examples/README.md index 8693d69..5577194 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,4 +1,5 @@ #Examples + This directory contains scripts along-with the .csv files of all datasets of RecDB's examples. In all, we have written scripts on four large datasets i.e MoiveTweet, MoiveLens 100k, MoiveLens 1M and yelps academic dataset. Following is the brief discription of the datasets: 1. MovieTweet: a rich data set consisting of ratings on movies that were contained in well-structured tweets on twitter. This data set consists 11495 ratings for 4730 movies rated from 5788 users. (1) users (userid, name):It consists all information of the registered user. (2) movies (movieid, name, year, genre): Information about movies are stored in this table. (3) ratings (userid, itemid, rating): Each tuple in the ratings table represents how much a user liked a movie after watching it. For further information about MovieTweet, please visit the following [https://github.com/sidooms/MovieTweetings](link).