77 *
88 *
99 * IDENTIFICATION
10- * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.44 1997/09/18 20:20:58 momjian Exp $
10+ * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.45 1997/10/12 07:09:20 vadim Exp $
1111 *
1212 *-------------------------------------------------------------------------
1313 */
@@ -303,6 +303,7 @@ static Query *
303303transformInsertStmt (ParseState * pstate ,AppendStmt * stmt )
304304{
305305Query * qry = makeNode (Query );/* make a new query tree */
306+ List * icolumns ;
306307
307308qry -> commandType = CMD_INSERT ;
308309pstate -> p_is_insert = true;
@@ -313,10 +314,74 @@ transformInsertStmt(ParseState *pstate, AppendStmt *stmt)
313314qry -> uniqueFlag = NULL ;
314315
315316/* fix the target list */
316- pstate -> p_insert_columns = makeTargetNames (pstate ,stmt -> cols );
317-
317+ icolumns = pstate -> p_insert_columns = makeTargetNames (pstate ,stmt -> cols );
318+
318319qry -> targetList = transformTargetList (pstate ,stmt -> targetList );
319-
320+
321+ /* DEFAULT handling */
322+ if (length (qry -> targetList )< pstate -> p_target_relation -> rd_att -> natts &&
323+ pstate -> p_target_relation -> rd_att -> constr &&
324+ pstate -> p_target_relation -> rd_att -> constr -> num_defval > 0 )
325+ {
326+ AttributeTupleForm * att = pstate -> p_target_relation -> rd_att -> attrs ;
327+ AttrDefault * defval = pstate -> p_target_relation -> rd_att -> constr -> defval ;
328+ int ndef = pstate -> p_target_relation -> rd_att -> constr -> num_defval ;
329+
330+ /*
331+ * if stmt->cols == NIL then makeTargetNames returns list of all
332+ * attrs: have to shorter icolumns list...
333+ */
334+ if (stmt -> cols == NIL )
335+ {
336+ List * extrl ;
337+ int i = length (qry -> targetList );
338+
339+ foreach (extrl ,icolumns )
340+ {
341+ if (-- i <=0 )
342+ break ;
343+ }
344+ freeList (lnext (extrl ));
345+ lnext (extrl )= NIL ;
346+ }
347+
348+ while (ndef -- > 0 )
349+ {
350+ List * tl ;
351+ Ident * id ;
352+ TargetEntry * te ;
353+
354+ foreach (tl ,icolumns )
355+ {
356+ id = (Ident * )lfirst (tl );
357+ if (!namestrcmp (& (att [defval [ndef ].adnum - 1 ]-> attname ),id -> name ))
358+ break ;
359+ }
360+ if (tl != NIL )/* something given for this attr */
361+ continue ;
362+ /*
363+ * Nothing given for this attr with DEFAULT expr, so
364+ * add new TargetEntry to qry->targetList.
365+ * Note, that we set resno to defval[ndef].adnum:
366+ * it's what transformTargetList()->make_targetlist_expr()
367+ * does for INSERT ... SELECT. But for INSERT ... VALUES
368+ * pstate->p_last_resno is used. It doesn't matter for
369+ * "normal" using (planner creates proper target list
370+ * in preptlist.c), but may break RULEs in some way.
371+ * It seems better to create proper target list here...
372+ */
373+ te = makeNode (TargetEntry );
374+ te -> resdom = makeResdom (defval [ndef ].adnum ,
375+ att [defval [ndef ].adnum - 1 ]-> atttypid ,
376+ att [defval [ndef ].adnum - 1 ]-> attlen ,
377+ pstrdup (nameout (& (att [defval [ndef ].adnum - 1 ]-> attname ))),
378+ 0 ,0 ,0 );
379+ te -> fjoin = NULL ;
380+ te -> expr = (Node * )stringToNode (defval [ndef ].adbin );
381+ qry -> targetList = lappend (qry -> targetList ,te );
382+ }
383+ }
384+
320385/* fix where clause */
321386qry -> qual = transformWhereClause (pstate ,stmt -> whereClause );
322387
@@ -1098,10 +1163,20 @@ makeTargetNames(ParseState *pstate, List *cols)
10981163}
10991164}
11001165else
1166+ {
11011167foreach (tl ,cols )
1102- /* elog on failure */
1103- varattno (pstate -> p_target_relation , ((Ident * )lfirst (tl ))-> name );
1104-
1168+ {
1169+ List * nxt ;
1170+ char * name = ((Ident * )lfirst (tl ))-> name ;
1171+
1172+ /* elog on failure */
1173+ varattno (pstate -> p_target_relation ,name );
1174+ foreach (nxt ,lnext (tl ))
1175+ if (!strcmp (name , ((Ident * )lfirst (nxt ))-> name ))
1176+ elog (WARN ,"Attribute %s should be specified only once" ,name );
1177+ }
1178+ }
1179+
11051180return cols ;
11061181}
11071182