पीवीएस-स्टूडियो ने अपाचे हाइव का दौरा किया

चित्र 1

पिछले दस वर्षों से, ओपन-सोर्स आंदोलन आईटी उद्योग के विकास के प्रमुख ड्राइवरों में से एक रहा है, और इसका महत्वपूर्ण घटक है। न केवल मात्रा के मामले में बल्कि गुणवत्ता के मामले में भी ओपन-सोर्स प्रोजेक्ट्स की भूमिका अधिक से अधिक प्रमुख होती जा रही है, जो सामान्य रूप से आईटी बाजार में कैसे तैनात हैं, इसकी अवधारणा को बदल देती है। हमारी साहसी पीवीएस-स्टूडियो टीम निष्क्रिय नहीं बैठ रही है और कोडबेस की भारी गहराई में छिपे हुए बग ढूंढकर और इस तरह की परियोजनाओं के लेखकों को मुफ्त लाइसेंस विकल्प की पेशकश करके ओपन-सोर्स सॉफ़्टवेयर की उपस्थिति को मजबूत करने में सक्रिय भाग ले रही है। यह लेख उस गतिविधि का सिर्फ एक और टुकड़ा है! आज हम अपाचे हाइव के बारे में बात करने जा रहे हैं। मुझे रिपोर्ट मिल गई है - और देखने लायक चीजें हैं।

पीवीएस-स्टूडियो के बारे में


स्थैतिक कोड विश्लेषक PVS-Studio , जो अब लगभग 10 वर्षों से अधिक समय से है, एक बहु-कार्यात्मक और आसान-से-एकीकृत सॉफ्टवेयर समाधान है। वर्तमान में, यह C, C ++, C #, और Java को सपोर्ट करता है और Windows, Linux, और macOS पर चलता है।

पीवीएस-स्टूडियो कई कंपनियों द्वारा कई टीमों द्वारा उपयोग किया जाने वाला एक सशुल्क बी 2 बी घोल है। यदि आप विश्लेषक का प्रयास करना चाहते हैं, तो वितरण डाउनलोड करने के लिए इस पृष्ठ पर जाएं और परीक्षण कुंजी का अनुरोध करें।

यदि आप एक ओपन-सोर्स geek हैं या, कहते हैं, एक छात्र, आप हमारे मुफ्त लाइसेंस विकल्पों में से एक का लाभ उठा सकते हैं।

अपाचे हाइव के बारे में


पिछले वर्षों में डेटा की मात्रा में भारी वृद्धि हुई है। मानक डेटाबेस अब इस तेजी से विकास का सामना नहीं कर सकते हैं, जहां बिग डेटा शब्द अन्य संबंधित धारणाओं (जैसे प्रसंस्करण, भंडारण और बड़े डेटा पर अन्य संचालन) के साथ आता है।

Apache Hadoop को वर्तमान में अग्रणी बिग डेटा तकनीकों में से एक माना जाता है। इसके प्राथमिक कार्य बड़ी मात्रा में डेटा का भंडारण, प्रसंस्करण और प्रबंधन कर रहे हैं। फ्रेमवर्क से युक्त मुख्य घटक हैं Hadoop Common, HDFS , Hadoop MapReduce , और Hadoop YARN । समय के साथ, संबंधित परियोजनाओं और प्रौद्योगिकियों का एक बड़ा पारिस्थितिकी तंत्र Hadoop के आसपास विकसित हुआ है, जिनमें से कई मूल रूप से परियोजना के हिस्से के रूप में शुरू हुए और फिर स्वतंत्र होने के लिए नवोदित थे। अपाचे हाइव उनमें से एक है।

अपाचे हाइव एक वितरित डेटा वेयरहाउस है। यह HDFS में संग्रहीत डेटा का प्रबंधन करता है और उस डेटा को संभालने के लिए SQL (HiveQL) पर आधारित क्वेरी भाषा प्रदान करता है। परियोजना पर अधिक विवरण यहां पाया जा सकता है

विश्लेषण चल रहा है


विश्लेषण शुरू करने में अधिक प्रयास या समय नहीं लगा। यहाँ मेरा एल्गोरिथ्म है:

  • GitHub से Apache Hive डाउनलोड किया गया;
  • जावा विश्लेषक शुरू करने पर गाइड पढ़ें और विश्लेषण लॉन्च किया;
  • विश्लेषक की रिपोर्ट मिली, इसका अध्ययन किया और सबसे दिलचस्प मामलों को लिखा।

विश्लेषण परिणाम इस प्रकार हैं: 6500+ फाइलों पर उच्च और मध्यम स्तर (क्रमशः 602 और 854) की 1456 चेतावनी।

सभी चेतावनियाँ वास्तविक बग का संदर्भ नहीं देती हैं। वह बिलकुल सामान्य है; इससे पहले कि आप इसे नियमित रूप से उपयोग करना शुरू करें, आपको विश्लेषक की सेटिंग्स को मोड़ना होगा। उसके बाद, आप आमतौर पर झूठी सकारात्मक ( उदाहरण ) की काफी कम दर की उम्मीद करते हैं।

मैंने 407 चेतावनियाँ (177 हाई- और 230 मीडियम-लेवल) को परीक्षण फाइलों से चालू कर दिया। मैंने V6022 डायग्नोस्टिक को भी नजरअंदाज कर दिया (क्योंकि जब आप कोड से परिचित नहीं हैं तो दोषपूर्ण और सही टुकड़ों में अंतर नहीं कर सकते हैं), जिसे 482 बार ट्रिगर किया गया था। न ही मैंने V6021 डायग्नोस्टिक द्वारा उत्पन्न 179 चेतावनियों की जांच की।

अंत में, मेरे पास अभी भी जाने के लिए पर्याप्त चेतावनी थी, और जब से मैंने सेटिंग्स को मोड़ नहीं दिया था, तब भी उनके बारे में कुछ प्रतिशत सकारात्मक सकारात्मकता है। इस तरह के एक लेख में बहुत सारी चेतावनियों सहित बस कोई मतलब नहीं है :)। तो हम सिर्फ इस बारे में बात करेंगे कि मेरी आंख ने क्या पकड़ा और काफी उत्सुक दिखे।

पूर्व निर्धारित स्थिति


इस विश्लेषण के लिए जांच किए गए निदानों में, V6007 जारी किए गए चेतावनियों की संख्या के लिए एक रिकॉर्ड रखता है। 200 से अधिक संदेश !!! कुछ हानिरहित दिखते हैं, अन्य संदिग्ध हैं, और कुछ अन्य सभी के बाद वास्तविक कीड़े हैं! आइए उनमें से कुछ पर एक नज़र डालें।

V6007 अभिव्यक्ति 'key.startsWith ("hplsql।")' हमेशा सच होता है। Exec.java (675)

void initOptions() { .... if (key == null || value == null || !key.startsWith("hplsql.")) { // <= continue; } else if (key.compareToIgnoreCase(Conf.CONN_DEFAULT) == 0) { .... } else if (key.startsWith("hplsql.conn.init.")) { .... } else if (key.startsWith(Conf.CONN_CONVERT)) { .... } else if (key.startsWith("hplsql.conn.")) { .... } else if (key.startsWith("hplsql.")) { // <= .... } } 

यह काफी लंबा है अगर और-अगर निर्माण! विश्लेषक अंतिम में स्थिति को पसंद नहीं करता है अगर (key.startsWith ("hplsql।")) क्योंकि यदि निष्पादन उस तक पहुंचता है, तो इसका मतलब यह सच है। वास्तव में, यदि आप इस पूरी इफ -और-अगर निर्माण की पहली पंक्ति को देखते हैं, तो आप देखेंगे कि इसमें पहले से ही विपरीत जांच शामिल है, इसलिए यदि स्ट्रिंग "hplsql" से शुरू नहीं होती है। , निष्पादन तुरंत अगले पुनरावृत्ति पर छोड़ देगा।

V6007 अभिव्यक्ति 'columnNameProperty.length () == 0' हमेशा गलत है। OrcRecordUpdater.java (238)

 private static TypeDescription getTypeDescriptionFromTableProperties(....) { .... if (tableProperties != null) { final String columnNameProperty = ....; final String columnTypeProperty = ....; if ( !Strings.isNullOrEmpty(columnNameProperty) && !Strings.isNullOrEmpty(columnTypeProperty)) { List<String> columnNames = columnNameProperty.length() == 0 ? new ArrayList<String>() : ....; List<TypeInfo> columnTypes = columnTypeProperty.length() == 0 ? new ArrayList<TypeInfo>() : ....; .... } } } .... } 

शून्य से कॉलमनामप्रॉपर्टी स्ट्रिंग की लंबाई की तुलना हमेशा झूठी होगी। ऐसा इसलिए होता है क्योंकि यह तुलना Strings.isNullOrEmpty (columnNameProperty) की जाँच करती है। इसलिए यदि निष्पादन हमारी स्थिति तक पहुंचता है, तो इसका मतलब होगा कि कॉलमनामप्रॉपर्टी स्ट्रिंग निश्चित रूप से न तो रिक्त है और न ही खाली है।

स्तंभ स्तंभप्राय स्ट्रिंग एक पंक्ति के लिए बाद में भी ऐसा ही है:

  • V6007 अभिव्यक्ति 'columnTypeProperty.length () == 0' हमेशा गलत है। OrcRecordUpdater.java (239)

V6007 अभिव्यक्ति 'colOrScalar1.equals ("कॉलम")' हमेशा गलत है। GenVectorCode.java (3469)

 private void generateDateTimeArithmeticIntervalYearMonth(String[] tdesc) throws Exception { .... String colOrScalar1 = tdesc[4]; .... String colOrScalar2 = tdesc[6]; .... if (colOrScalar1.equals("Col") && colOrScalar1.equals("Column")) // <= { .... } else if (colOrScalar1.equals("Col") && colOrScalar1.equals("Scalar")) { .... } else if (colOrScalar1.equals("Scalar") && colOrScalar1.equals("Column")) { .... } } 

अच्छा पुराना कॉपी-पेस्ट। वर्तमान तर्क के दृष्टिकोण से, स्ट्रिंग colOrScalar1 में एक साथ दो अलग-अलग मूल्य हो सकते हैं, जो असंभव है। जाहिर है, चेक में बाईं ओर चर colOrScalar1 और दाईं ओर colOrScalar2 होना चाहिए।

इसी तरह की चेतावनी नीचे कुछ पंक्तियाँ:

  • V6007 अभिव्यक्ति 'colOrScalar1.equals ("स्केलर") हमेशा गलत है। GenVectorCode.java (3475)
  • V6007 अभिव्यक्ति 'colOrScalar1.equals ("कॉलम")' हमेशा गलत है। GenVectorCode.java (3486)

नतीजतन, यह if-else-if निर्माण कभी भी कुछ नहीं करेगा।

कुछ और V6007 चेतावनी:

  • V6007 अभिव्यक्ति 'वर्ण == अशक्त' हमेशा गलत है। RandomTypeUtil.java (43)
  • V6007 अभिव्यक्ति 'writeIdHwm> 0' हमेशा गलत है। TxnHandler.java (1603)
  • V6007 अभिव्यक्ति 'फ़ील्ड। असेंबल ("*")' हमेशा सही होती है। Server.java (983)
  • V6007 अभिव्यक्ति 'currentGroups! = नल' हमेशा सच है। GenericUDFCurrentGroups.java (90)
  • V6007 अभिव्यक्ति 'this.wh == null' हमेशा झूठी होती है। नया विवरण नहीं-शून्य संदर्भ। स्टोरेजबेडअथोराइजेशनप्रोवाइडर.जाव (93), स्टोरेजबेडअथोरीकरणप्रोवाइडर.जॉव (92)
  • और इसी तरह ...

एनपीई


V6008 'डगलॉक' की संभावित अशक्तता। QueryTracker.java (557), QueryTracker.java (553)

 private void handleFragmentCompleteExternalQuery(QueryInfo queryInfo) { if (queryInfo.isExternalQuery()) { ReadWriteLock dagLock = getDagLock(queryInfo.getQueryIdentifier()); if (dagLock == null) { LOG.warn("Ignoring fragment completion for unknown query: {}", queryInfo.getQueryIdentifier()); } boolean locked = dagLock.writeLock().tryLock(); ..... } } 

एक अशक्त वस्तु पकड़ी जाती है, लॉग की जाती है, और ... कार्यक्रम बस चलता रहता है। नतीजतन, चेक का एक शून्य पॉइंटर डेरेफेरेंस होता है। आउच!

डेवलपर्स को वास्तव में कार्यक्रम से बाहर निकलने या शून्य संदर्भ प्राप्त करने के मामले में कुछ विशेष अपवाद को फेंकना चाहिए था।

V6008 समारोह 'अनलॉक' में 'बफर' के अशांति को रोकने के लिए 'बफ़र'। मेटाडेटाचेजावा (410), मेटाडेटाचेजावा (465)

 private boolean lockBuffer(LlapBufferOrBuffers buffers, ....) { LlapAllocatorBuffer buffer = buffers.getSingleLlapBuffer(); if (buffer != null) { // <= return lockOneBuffer(buffer, doNotifyPolicy); } LlapAllocatorBuffer[] bufferArray = buffers.getMultipleLlapBuffers(); for (int i = 0; i < bufferArray.length; ++i) { if (lockOneBuffer(bufferArray[i], doNotifyPolicy)) continue; for (int j = 0; j < i; ++j) { unlockSingleBuffer(buffer, true); // <= } .... } .... } .... private void unlockSingleBuffer(LlapAllocatorBuffer buffer, ....) { boolean isLastDecref = (buffer.decRef() == 0); // <= if (isLastDecref) { .... } } 

एक और संभावित एनपीई। यदि निष्पादन unlockSleleBuffer विधि तक पहुंचता है, तो इसका मतलब होगा कि बफर ऑब्जेक्ट शून्य है। मान लीजिए कि यह क्या हो गया है! यदि आप unlockSlele बफ़र विधि को देखते हैं , तो आप देखेंगे कि हमारी वस्तु को पहली पंक्ति में कैसे सही रूप से परिभाषित किया गया है। पकड़ लिया!

एक पारी में बवाल मच गया


V6034 शिफ्ट के मान से 'bitShiftsInWord - 1' प्रकार के आकार के साथ असंगत हो सकता है: 'bitShiftsInWord - 1' = [-1 ... 30]। अनसाइन्टइंटेंट २००s.जावा (१igned ९ १)

 private void shiftRightDestructive(int wordShifts, int bitShiftsInWord, boolean roundUp) { if (wordShifts == 0 && bitShiftsInWord == 0) { return; } assert (wordShifts >= 0); assert (bitShiftsInWord >= 0); assert (bitShiftsInWord < 32); if (wordShifts >= 4) { zeroClear(); return; } final int shiftRestore = 32 - bitShiftsInWord; // check this because "123 << 32" will be 123. final boolean noRestore = bitShiftsInWord == 0; final int roundCarryNoRestoreMask = 1 << 31; final int roundCarryMask = (1 << (bitShiftsInWord - 1)); // <= .... } 

यह -1 द्वारा संभावित बदलाव है। यदि विधि को कहा जाता है, तो, शब्दशः == 3 और बिटशिफ्टइंडवर्ल्ड == 0 को सूचित करें, रिपोर्ट की गई पंक्ति 1 << -1 के साथ समाप्त हो जाएगी। क्या वह नियोजित व्यवहार है?

V6034 शिफ्ट 'जे' के मान से आकार के अनुसार असंगत हो सकता है: 'जे' = [0 ... 63]। IoTrace.java (272)

 public void logSargResult(int stripeIx, boolean[] rgsToRead) { .... for (int i = 0, valOffset = 0; i < elements; ++i, valOffset += 64) { long val = 0; for (int j = 0; j < 64; ++j) { int ix = valOffset + j; if (rgsToRead.length == ix) break; if (!rgsToRead[ix]) continue; val = val | (1 << j); // <= } .... } .... } 

रिपोर्ट की गई लाइन में, j वैरिएबल की रेंज [0 ... 63] के भीतर मान हो सकती है। उसके कारण, लूप में वैल के मूल्य की गणना अप्रत्याशित तरीके से चल सकती है। (1 << j) अभिव्यक्ति में, मान 1 प्रकार का इंट होता है , इसलिए इसे 32 बिट्स द्वारा शिफ्ट करना और अधिक हमें टाइप की सीमा से परे ले जाता है। यह लिखकर तय किया जा सकता है ((लंबा) 1 << j)

प्रवेश करके दूर किया जा रहा है


V6046 गलत प्रारूप। विभिन्न प्रकार के प्रारूप आइटम अपेक्षित हैं। उपयोग नहीं किए गए तर्क: 1, 2. आँकड़े। जजाव (89)

 private static ImmutableList<PersistedRuntimeStats> extractStatsFromPlanMapper (....) { .... if (stat.size() > 1 || sig.size() > 1) { StringBuffer sb = new StringBuffer(); sb.append(String.format( "expected(stat-sig) 1-1, got {}-{} ;", // <= stat.size(), sig.size() )); .... } .... if (e.getAll(OperatorStats.IncorrectRuntimeStatsMarker.class).size() > 0) { LOG.debug( "Ignoring {}, marked with OperatorStats.IncorrectRuntimeStatsMarker", sig.get(0) ); continue; } .... } 

String.format () का उपयोग करके स्ट्रिंग को प्रारूपित करने के लिए कोड लिखते समय, डेवलपर ने गलत सिंटैक्स का उपयोग किया। नतीजतन, पारित मापदंडों ने इसे परिणामस्वरूप स्ट्रिंग में कभी नहीं बनाया। मेरा अनुमान है कि डेवलपर इसे लिखने से पहले लॉगिंग पर काम कर रहा था, जहां से उन्होंने सिंटैक्स उधार लिया था।

एक चोरी अपवाद


V6051 'अंत' ब्लॉक में 'रिटर्न' स्टेटमेंट के उपयोग से अनचाहे अपवादों का नुकसान हो सकता है। ObjectStore.java (9080)

 private List<MPartitionColumnStatistics> getMPartitionColumnStatistics(....) throws NoSuchObjectException, MetaException { boolean committed = false; try { .... /*some actions*/ committed = commitTransaction(); return result; } catch (Exception ex) { LOG.error("Error retrieving statistics via jdo", ex); if (ex instanceof MetaException) { throw (MetaException) ex; } throw new MetaException(ex.getMessage()); } finally { if (!committed) { rollbackTransaction(); return Lists.newArrayList(); } } } 

अंत में ब्लॉक से कुछ भी वापस करना एक बहुत बुरा अभ्यास है, और यह उदाहरण स्पष्ट रूप से दिखाता है कि क्यों।

कोशिश ब्लॉक में, कार्यक्रम एक अनुरोध बना रहा है और भंडारण तक पहुंच बना रहा है। प्रतिबद्ध चर में डिफ़ॉल्ट रूप से मान गलत होता है और कोशिश ब्लॉक में सभी पिछले कार्यों को सफलतापूर्वक निष्पादित किए जाने के बाद ही अपना राज्य बदलता है। इसका अर्थ है कि यदि कोई अपवाद उठाया जाता है, तो वह चर हमेशा गलत होगापकड़ ब्लॉक अपवाद को पकड़ेगा, इसे थोड़ा समायोजित करेगा, और इसे फेंक देगा। इसलिए जब यह अंततः ब्लॉक की बारी है, तो निष्पादन उस स्थिति में प्रवेश करेगा जहां से एक खाली सूची वापस आ जाएगी। इस रिटर्न से हमें क्या फायदा होगा? ठीक है, यह हमें किसी भी पकड़े गए अपवाद को बाहर की तरफ फेंकने से रोकने में खर्च करता है जहां इसे ठीक से संभाला जा सकता है। विधि के हस्ताक्षर में निर्दिष्ट कोई भी अपवाद कभी नहीं फेंका जाएगा; वे केवल भ्रामक हैं।

एक समान नैदानिक ​​संदेश:

  • V6051 'अंत' ब्लॉक में 'रिटर्न' स्टेटमेंट के उपयोग से अनचाहे अपवादों का नुकसान हो सकता है। ObjectStore.java (808)

विविध


V6009 फ़ंक्शन 'तुलना' को एक विषम तर्क प्राप्त होता है। एक ऑब्जेक्ट 'o2.getWorkerIdentity ()' का उपयोग अपनी स्वयं की पद्धति के तर्क के रूप में किया जाता है। LlapFixedRegistryImpl.java (244)

 @Override public List<LlapServiceInstance> getAllInstancesOrdered(....) { .... Collections.sort(list, new Comparator<LlapServiceInstance>() { @Override public int compare(LlapServiceInstance o1, LlapServiceInstance o2) { return o2.getWorkerIdentity().compareTo(o2.getWorkerIdentity()); // <= } }); .... } 

इस तरह की मूर्खतापूर्ण गलती के लिए कई कारण हो सकते हैं: कॉपी-पेस्ट, लापरवाही, जल्दी, और इसी तरह। हम अक्सर ओपन-सोर्स प्रोजेक्ट्स में इस तरह की त्रुटियां देखते हैं और यहां तक ​​कि उस बारे में एक पूरा लेख भी।

V6020 को शून्य से विभाजित करें। 'भाजक' भाजक मानों की श्रेणी में शून्य शामिल है। SqlMathUtil.java (265)

 public static long divideUnsignedLong(long dividend, long divisor) { if (divisor < 0L) { /*some comments*/ return (compareUnsignedLong(dividend, divisor)) < 0 ? 0L : 1L; } if (dividend >= 0) { // Both inputs non-negative return dividend / divisor; // <= } else { .... } } 

यह काफी तुच्छ है। चेक की एक श्रृंखला को शून्य से विभाजित करने के लिए असहाय था।

कुछ और चेतावनियाँ:

  • V6020 मॉड शून्य से। 'भाजक' भाजक मानों की श्रेणी में शून्य शामिल है। SqlMathUtil.java (309)
  • V6020 को शून्य से विभाजित करें। 'भाजक' भाजक मानों की श्रेणी में शून्य शामिल है। SqlMathUtil.java (276)
  • V6020 को शून्य से विभाजित करें। 'भाजक' भाजक मानों की श्रेणी में शून्य शामिल है। SqlMathUtil.java (312)

V6030 की विधि 'के दाईं ओर स्थित है।' ऑपरेटर को बाएं ऑपरेंड के मूल्य की परवाह किए बिना बुलाया जाएगा। शायद, '' का उपयोग करना बेहतर है। OperatorUtils.java (573)

 public static Operator<? extends OperatorDesc> findSourceRS(....) { .... List<Operator<? extends OperatorDesc>> parents = ....; if (parents == null | parents.isEmpty()) { // reached end eg TS operator return null; } .... } 

प्रोग्रामर ने बिटवाइन ऑपरेटर को लिखा | तार्किक के बजाय || इसका मतलब यह है कि दाहिने हिस्से को निष्पादित किया जाएगा, चाहे वह बाएं के परिणाम के साथ हो। यदि माता-पिता == अशक्त हैं , तो यह टाइपो अगले तार्किक उपसंचाई में एनपीई अधिकार के साथ समाप्त हो जाएगा।

V6042 अभिव्यक्ति 'A' के साथ संगतता के लिए जाँच की जाती है, लेकिन 'B' टाइप करने के लिए डाली जाती है। वेक्टरकॉल्यूमनएसिग्निफैक्टरी.जावा (347)

 public static VectorColumnAssign buildObjectAssign(VectorizedRowBatch outputBatch, int outColIndex, PrimitiveCategory category) throws HiveException { VectorColumnAssign outVCA = null; ColumnVector destCol = outputBatch.cols[outColIndex]; if (destCol == null) { .... } else if (destCol instanceof LongColumnVector) { switch(category) { .... case LONG: outVCA = new VectorLongColumnAssign() { .... } .init(.... , (LongColumnVector) destCol); break; case TIMESTAMP: outVCA = new VectorTimestampColumnAssign() { .... }.init(...., (TimestampColumnVector) destCol); // <= break; case DATE: outVCA = new VectorLongColumnAssign() { .... } .init(...., (LongColumnVector) destCol); break; case INTERVAL_YEAR_MONTH: outVCA = new VectorLongColumnAssign() { .... }.init(...., (LongColumnVector) destCol); break; case INTERVAL_DAY_TIME: outVCA = new VectorIntervalDayTimeColumnAssign() { .... }.init(...., (IntervalDayTimeColumnVector) destCol);// <= break; default: throw new HiveException(....); } } else if (destCol instanceof DoubleColumnVector) { .... } .... else { throw new HiveException(....); } return outVCA; } 

हम कक्षाओं में रुचि रखते हैं LongColumnVector ColumnVector का विस्तार करता है और TimestampColumnVector ColumnVector का विस्तार करता हैचेककोल ऑब्जेक्ट, जो कि लार्जकॉल्यूमिनेटर का एक उदाहरण है, स्पष्ट रूप से बताता है कि यह इस वर्ग की एक वस्तु है जिसे सशर्त विवरण के शरीर से निपटा जाएगा। हालांकि, इसके बावजूद, यह अभी भी टाइमस्टैम्पकॉल्यूमिनेक्टर के लिए डाली गई है! जैसा कि आप देख सकते हैं, ये अलग-अलग वर्ग हैं सिवाय इसके कि वे एक ही माता-पिता से प्राप्त होते हैं। नतीजतन, हमें एक क्लासकैस्ट अपवाद प्राप्त होता है।

IntervalDayTimeColumnVector के लिए कास्टिंग के मामले में भी यही सच है:

  • V6042 अभिव्यक्ति 'A' के साथ संगतता के लिए जाँच की जाती है, लेकिन 'B' टाइप करने के लिए डाली जाती है। वेक्टरकॉल्यूमनएसिग्नेटफैक्टिंग.जवा (390)

V6060 शून्य से सत्यापित होने से पहले 'var' संदर्भ का उपयोग किया गया था। वर.जावा (402), वर.जावा (395)

 @Override public boolean equals(Object obj) { if (getClass() != obj.getClass()) { // <= return false; } Var var = (Var)obj; if (this == var) { return true; } else if (var == null || // <= var.value == null || this.value == null) { return false; } .... } 

यहाँ आपको अशक्तता के लिए var ऑब्जेक्ट की एक अजीब जाँच दिखाई देती है, क्योंकि पहले से ही डिरेलमेंट हो चुका है। इस संदर्भ में, var और obj एक ही ऑब्जेक्ट ( var = (Var) obj ) हैं। नल चेक की उपस्थिति का अर्थ है कि पारित ऑब्जेक्ट शून्य हो सकता है। तो बराबर (शून्य) कॉल करने पर पहली पंक्ति में, सही गलत के बजाय, NPE परिणाम होगा। हां, चेक वहीं है, लेकिन दुख की बात है कि यह गलत जगह है।

कुछ अन्य समान मामले, जहां चेक से पहले एक वस्तु का उपयोग किया जाता है:

  • V6060 नल के खिलाफ सत्यापित होने से पहले 'मान' संदर्भ का उपयोग किया गया था। ParquetRecordReaderWrapper.java (168), ParquetRecordReaderWrapper.java (166)
  • V6060 'defaultConstraintCols' संदर्भ का उपयोग शून्य से पहले सत्यापित किए जाने से पहले किया गया था। HiveMetaStore.java (2539), HiveMetaStore.java (2530)
  • V6060 'projIndxLst' संदर्भ का उपयोग इससे पहले कि यह अशक्त के खिलाफ सत्यापित किया गया था। RelOptHiveTable.java (683), RelOptHiveTable.java (682)
  • V6060 नल के खिलाफ सत्यापित होने से पहले 'पुराने' संदर्भ का उपयोग किया गया था। ObjectStore.java (4343), ObjectStore.java (4339)
  • और इसी तरह ...

निष्कर्ष


यदि आप कभी भी अपने आप को बिग डेटा में रुचि रखते हैं यदि केवल थोड़ा सा, तो आप शायद ही अनजान हो सकते हैं कि अपाचे हाइव कितना महत्वपूर्ण है। यह एक लोकप्रिय परियोजना है, और काफी बड़ी एक है, जिसमें 6500 से अधिक स्रोत फाइलें (* .java) शामिल हैं। कई डेवलपर्स इसे कई वर्षों से लिख रहे हैं, जिसका अर्थ है कि एक स्थिर विश्लेषक के लिए बहुत सी चीजें हैं जो वहां मिल सकती हैं। यह सिर्फ एक और समय साबित करता है कि मध्यम और बड़ी परियोजनाओं को विकसित करते समय स्थैतिक विश्लेषण बेहद महत्वपूर्ण और उपयोगी है!

नोट। एकल-समय की जांच जैसे मैंने यहां की थी, विश्लेषक की क्षमताओं को दिखाने के लिए अच्छी हैं, लेकिन इसका उपयोग करने के लिए पूरी तरह से अनुचित परिदृश्य हैं। यह विचार यहाँ और यहाँ पर विस्तृत है । स्थैतिक विश्लेषण नियमित रूप से इस्तेमाल किया जाना है!

हाइव के इस चेक से काफी कुछ दोष और संदिग्ध अंश सामने आए। यदि अपाचे हाइव के लेखक इस लेख में आते हैं, तो हमें परियोजना को बेहतर बनाने में कड़ी मेहनत के साथ मदद करने में खुशी होगी।

आप अपाचे Hadoop के बिना अपाचे हाइव की कल्पना नहीं कर सकते हैं, इसलिए पीवीएस-स्टूडियो से गेंडा अच्छी तरह से उस एक को भी यात्रा का भुगतान कर सकता है। लेकिन आज के लिए बस इतना ही। इस बीच, मैं आपको विश्लेषक डाउनलोड करने और अपनी खुद की परियोजनाओं की जांच करने के लिए आमंत्रित करता हूं।

Source: https://habr.com/ru/post/hi463753/


All Articles