@@ -22,8 +22,9 @@ import scala.collection.mutable
2222import org .json4s .JsonAST .{JArray , JString }
2323import org .json4s .jackson .JsonMethods ._
2424
25+ import org .apache .spark .internal .Logging
2526import org .apache .spark .sql .{AnalysisException , Row , SparkSession }
26- import org .apache .spark .sql .catalyst .{FunctionIdentifier , TableIdentifier }
27+ import org .apache .spark .sql .catalyst .{FunctionIdentifier , SQLConfHelper , TableIdentifier }
2728import org .apache .spark .sql .catalyst .analysis .{GlobalTempView , LocalTempView , PersistedView , ViewType }
2829import org .apache .spark .sql .catalyst .catalog .{CatalogStorageFormat , CatalogTable , CatalogTableType , SessionCatalog , TemporaryViewRelation }
2930import org .apache .spark .sql .catalyst .expressions .{Alias , Attribute , SubqueryExpression , UserDefinedExpression }
@@ -115,48 +116,27 @@ case class CreateViewCommand(
115116
116117 if (viewType == LocalTempView ) {
117118 val aliasedPlan = aliasPlan(sparkSession, analyzedPlan)
118- if (replace && needsToUncache(catalog.getRawTempView(name.table), aliasedPlan)) {
119- logInfo(s " Try to uncache ${name.quotedString} before replacing. " )
120- checkCyclicViewReference(analyzedPlan, Seq (name), name)
121- CommandUtils .uncacheTableOrView(sparkSession, name.quotedString)
122- }
123- // If there is no sql text (e.g. from Dataset API), we will always store the analyzed plan
124- val tableDefinition = if (! conf.storeAnalyzedPlanForView && originalText.nonEmpty) {
125- TemporaryViewRelation (
126- prepareTemporaryView(
127- name,
128- sparkSession,
129- analyzedPlan,
130- aliasedPlan.schema,
131- originalText))
132- } else {
133- TemporaryViewRelation (
134- prepareTemporaryViewFromDataFrame(name, aliasedPlan),
135- Some (aliasedPlan))
136- }
119+ val tableDefinition = createTemporaryViewRelation(
120+ name,
121+ sparkSession,
122+ replace,
123+ catalog.getRawTempView(name.table),
124+ originalText,
125+ aliasedPlan,
126+ analyzedPlan)
137127 catalog.createTempView(name.table, tableDefinition, overrideIfExists = replace)
138128 } else if (viewType == GlobalTempView ) {
139129 val db = sparkSession.sessionState.conf.getConf(StaticSQLConf .GLOBAL_TEMP_DATABASE )
140130 val viewIdent = TableIdentifier (name.table, Option (db))
141131 val aliasedPlan = aliasPlan(sparkSession, analyzedPlan)
142- if (replace && needsToUncache(catalog.getRawGlobalTempView(name.table), aliasedPlan)) {
143- logInfo(s " Try to uncache ${viewIdent.quotedString} before replacing. " )
144- checkCyclicViewReference(analyzedPlan, Seq (viewIdent), viewIdent)
145- CommandUtils .uncacheTableOrView(sparkSession, viewIdent.quotedString)
146- }
147- val tableDefinition = if (! conf.storeAnalyzedPlanForView && originalText.nonEmpty) {
148- TemporaryViewRelation (
149- prepareTemporaryView(
150- viewIdent,
151- sparkSession,
152- analyzedPlan,
153- aliasedPlan.schema,
154- originalText))
155- } else {
156- TemporaryViewRelation (
157- prepareTemporaryViewFromDataFrame(name, aliasedPlan),
158- Some (aliasedPlan))
159- }
132+ val tableDefinition = createTemporaryViewRelation(
133+ viewIdent,
134+ sparkSession,
135+ replace,
136+ catalog.getRawGlobalTempView(name.table),
137+ originalText,
138+ aliasedPlan,
139+ analyzedPlan)
160140 catalog.createGlobalTempView(name.table, tableDefinition, overrideIfExists = replace)
161141 } else if (catalog.tableExists(name)) {
162142 val tableMetadata = catalog.getTableMetadata(name)
@@ -192,20 +172,6 @@ case class CreateViewCommand(
192172 Seq .empty[Row ]
193173 }
194174
195- /**
196- * Checks if need to uncache the temp view being replaced.
197- */
198- private def needsToUncache (
199- rawTempView : Option [LogicalPlan ],
200- aliasedPlan : LogicalPlan ): Boolean = rawTempView match {
201- // The temp view doesn't exist, no need to uncache.
202- case None => false
203- // Do not need to uncache if the to-be-replaced temp view plan and the new plan are the
204- // same-result plans.
205- case Some (TemporaryViewRelation (_, Some (p))) => ! p.sameResult(aliasedPlan)
206- case Some (p) => ! p.sameResult(aliasedPlan)
207- }
208-
209175 /**
210176 * If `userSpecifiedColumns` is defined, alias the analyzed plan to the user specified columns,
211177 * else return the analyzed plan directly.
@@ -284,14 +250,21 @@ case class AlterViewAsCommand(
284250 }
285251
286252 private def alterTemporaryView (session : SparkSession , analyzedPlan : LogicalPlan ): Unit = {
287- val tableDefinition = if (conf.storeAnalyzedPlanForView) {
288- analyzedPlan
253+ val catalog = session.sessionState.catalog
254+ val rawTempView = if (name.database.isEmpty) {
255+ catalog.getRawTempView(name.table)
289256 } else {
290- checkCyclicViewReference(analyzedPlan, Seq (name), name)
291- TemporaryViewRelation (
292- prepareTemporaryView(
293- name, session, analyzedPlan, analyzedPlan.schema, Some (originalText)))
257+ catalog.getRawGlobalTempView(name.table)
294258 }
259+ assert(rawTempView.isDefined)
260+ val tableDefinition = createTemporaryViewRelation(
261+ name,
262+ session,
263+ replace = false ,
264+ rawTempView = rawTempView,
265+ originalText = Some (originalText),
266+ aliasedPlan = analyzedPlan,
267+ analyzedPlan = analyzedPlan)
295268 session.sessionState.catalog.alterTempViewDefinition(name, tableDefinition)
296269 }
297270
@@ -345,7 +318,7 @@ case class ShowViewsCommand(
345318 }
346319}
347320
348- object ViewHelper {
321+ object ViewHelper extends SQLConfHelper with Logging {
349322
350323 private val configPrefixDenyList = Seq (
351324 SQLConf .MAX_NESTED_VIEW_DEPTH .key,
@@ -592,19 +565,62 @@ object ViewHelper {
592565 (collectTempViews(child), collectTempFunctions(child))
593566 }
594567
568+ def createTemporaryViewRelation (
569+ name : TableIdentifier ,
570+ session : SparkSession ,
571+ replace : Boolean ,
572+ rawTempView : Option [LogicalPlan ],
573+ originalText : Option [String ],
574+ aliasedPlan : LogicalPlan ,
575+ analyzedPlan : LogicalPlan ): TemporaryViewRelation = {
576+ val needsToUncache = needsToUncacheTempView(rawTempView, aliasedPlan)
577+ if (replace && needsToUncache) {
578+ logInfo(s " Try to uncache ${name.quotedString} before replacing. " )
579+ checkCyclicViewReference(analyzedPlan, Seq (name), name)
580+ CommandUtils .uncacheTableOrView(session, name.quotedString)
581+ }
582+ if (! conf.storeAnalyzedPlanForView && originalText.nonEmpty) {
583+ TemporaryViewRelation (
584+ prepareTemporaryView(
585+ name,
586+ session,
587+ analyzedPlan,
588+ aliasedPlan.schema,
589+ originalText.get))
590+ } else {
591+ TemporaryViewRelation (
592+ prepareTemporaryViewFromDataFrame(name, aliasedPlan),
593+ Some (aliasedPlan))
594+ }
595+ }
596+
597+ /**
598+ * Checks if we need to uncache the temp view being replaced by checking if the raw temp
599+ * view will return the same result as the given aliased plan.
600+ */
601+ private def needsToUncacheTempView (
602+ rawTempView : Option [LogicalPlan ],
603+ aliasedPlan : LogicalPlan ): Boolean = rawTempView match {
604+ // The temp view doesn't exist, no need to uncache.
605+ case None => false
606+ // Do not need to uncache if the to-be-replaced temp view plan and the new plan are the
607+ // same-result plans.
608+ case Some (TemporaryViewRelation (_, Some (p))) => ! p.sameResult(aliasedPlan)
609+ case Some (p) => ! p.sameResult(aliasedPlan)
610+ }
595611
596612 /**
597613 * Returns a [[CatalogTable ]] that contains information for temporary view.
598614 * Generate the view-specific properties(e.g. view default database, view query output
599615 * column names) and store them as properties in the CatalogTable, and also creates
600616 * the proper schema for the view.
601617 */
602- def prepareTemporaryView (
618+ private def prepareTemporaryView (
603619 viewName : TableIdentifier ,
604620 session : SparkSession ,
605621 analyzedPlan : LogicalPlan ,
606622 viewSchema : StructType ,
607- originalText : Option [ String ] ): CatalogTable = {
623+ originalText : String ): CatalogTable = {
608624
609625 val catalog = session.sessionState.catalog
610626 val (tempViews, tempFunctions) = collectTemporaryObjects(catalog, analyzedPlan)
@@ -618,15 +634,15 @@ object ViewHelper {
618634 tableType = CatalogTableType .VIEW ,
619635 storage = CatalogStorageFormat .empty,
620636 schema = viewSchema,
621- viewText = originalText,
637+ viewText = Some ( originalText) ,
622638 properties = newProperties)
623639 }
624640
625641 /**
626642 * Returns a [[CatalogTable ]] that contains information for the temporary view created
627643 * from a dataframe.
628644 */
629- def prepareTemporaryViewFromDataFrame (
645+ private def prepareTemporaryViewFromDataFrame (
630646 viewName : TableIdentifier ,
631647 analyzedPlan : LogicalPlan ): CatalogTable = {
632648 CatalogTable (
0 commit comments